]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
UefiCpuPkg/CpuS3DataDxe: Keep old data if value already existed.
[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
15This program and the accompanying materials\r
16are licensed and made available under the terms and conditions of the BSD License\r
17which accompanies this distribution. The full text of the license may be found at\r
18http://opensource.org/licenses/bsd-license.php\r
19\r
20THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
21WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
22\r
23**/\r
24\r
25#include <PiDxe.h>\r
26\r
27#include <AcpiCpuData.h>\r
28\r
29#include <Library/BaseLib.h>\r
30#include <Library/BaseMemoryLib.h>\r
31#include <Library/UefiBootServicesTableLib.h>\r
32#include <Library/DebugLib.h>\r
33#include <Library/MtrrLib.h>\r
b5817210 34#include <Library/MemoryAllocationLib.h>\r
bfec5efa
MK
35\r
36#include <Protocol/MpService.h>\r
37#include <Guid/EventGroup.h>\r
38\r
39//\r
40// Data structure used to allocate ACPI_CPU_DATA and its supporting structures\r
41//\r
42typedef struct {\r
43 ACPI_CPU_DATA AcpiCpuData;\r
44 MTRR_SETTINGS MtrrTable;\r
45 IA32_DESCRIPTOR GdtrProfile;\r
46 IA32_DESCRIPTOR IdtrProfile;\r
47} ACPI_CPU_DATA_EX;\r
48\r
49/**\r
6eab8b43 50 Allocate EfiACPIMemoryNVS memory.\r
bfec5efa
MK
51\r
52 @param[in] Size Size of memory to allocate.\r
53\r
54 @return Allocated address for output.\r
55\r
56**/\r
57VOID *\r
6eab8b43 58AllocateAcpiNvsMemory (\r
bfec5efa
MK
59 IN UINTN Size\r
60 )\r
61{\r
62 EFI_PHYSICAL_ADDRESS Address;\r
63 EFI_STATUS Status;\r
64 VOID *Buffer;\r
65\r
bfec5efa 66 Status = gBS->AllocatePages (\r
6eab8b43 67 AllocateAnyPages,\r
bfec5efa
MK
68 EfiACPIMemoryNVS,\r
69 EFI_SIZE_TO_PAGES (Size),\r
70 &Address\r
71 );\r
72 if (EFI_ERROR (Status)) {\r
73 return NULL;\r
74 }\r
75\r
76 Buffer = (VOID *)(UINTN)Address;\r
77 ZeroMem (Buffer, Size);\r
78\r
79 return Buffer;\r
80}\r
81\r
b5817210
ED
82/**\r
83 Allocate memory and clean it with zero.\r
84\r
85 @param[in] Size Size of memory to allocate.\r
86\r
87 @return Allocated address for output.\r
88\r
89**/\r
90VOID *\r
91AllocateZeroPages (\r
92 IN UINTN Size\r
93 )\r
94{\r
95 VOID *Buffer;\r
96\r
97 Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));\r
98 if (Buffer != NULL) {\r
99 ZeroMem (Buffer, Size);\r
100 }\r
101\r
102 return Buffer;\r
103}\r
bfec5efa
MK
104/**\r
105 Callback function executed when the EndOfDxe event group is signaled.\r
106\r
65b24ada 107 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
bfec5efa
MK
108\r
109 @param[in] Event Event whose notification function is being invoked.\r
110 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.\r
111**/\r
112VOID\r
113EFIAPI\r
65b24ada 114CpuS3DataOnEndOfDxe (\r
bfec5efa
MK
115 IN EFI_EVENT Event,\r
116 OUT VOID *Context\r
117 )\r
118{\r
65b24ada
JF
119 EFI_STATUS Status;\r
120 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
121\r
122 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *) Context;\r
123 //\r
124 // Allocate a 4KB reserved page below 1MB\r
125 //\r
126 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;\r
127 Status = gBS->AllocatePages (\r
128 AllocateMaxAddress,\r
129 EfiReservedMemoryType,\r
130 1,\r
131 &AcpiCpuDataEx->AcpiCpuData.StartupVector\r
132 );\r
133 ASSERT_EFI_ERROR (Status);\r
134\r
bfec5efa 135 DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));\r
65b24ada 136 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
bfec5efa
MK
137\r
138 //\r
139 // Close event, so it will not be invoked again.\r
140 //\r
141 gBS->CloseEvent (Event);\r
142}\r
143\r
144/**\r
145 The entry function of the CpuS3Data driver.\r
146\r
147 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the\r
148 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid\r
149 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set\r
150 to the address that ACPI_CPU_DATA is allocated at.\r
151\r
152 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
153 @param[in] SystemTable A pointer to the EFI System Table.\r
154\r
155 @retval EFI_SUCCESS The entry point is executed successfully.\r
ca98f603 156 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
bfec5efa
MK
157 @retval other Some error occurs when executing this entry point.\r
158\r
159**/\r
160EFI_STATUS\r
161EFIAPI\r
162CpuS3DataInitialize (\r
163 IN EFI_HANDLE ImageHandle,\r
164 IN EFI_SYSTEM_TABLE *SystemTable\r
165 )\r
166{\r
167 EFI_STATUS Status;\r
168 ACPI_CPU_DATA_EX *AcpiCpuDataEx;\r
169 ACPI_CPU_DATA *AcpiCpuData;\r
170 EFI_MP_SERVICES_PROTOCOL *MpServices;\r
171 UINTN NumberOfCpus;\r
172 UINTN NumberOfEnabledProcessors;\r
173 VOID *Stack;\r
174 UINTN TableSize;\r
175 CPU_REGISTER_TABLE *RegisterTable;\r
176 UINTN Index;\r
177 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;\r
178 UINTN GdtSize;\r
179 UINTN IdtSize;\r
180 VOID *Gdt;\r
181 VOID *Idt;\r
182 EFI_EVENT Event;\r
8b371e93 183 ACPI_CPU_DATA *OldAcpiCpuData;\r
bfec5efa 184\r
ca98f603
SZ
185 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
186 return EFI_UNSUPPORTED;\r
187 }\r
188\r
8b371e93
JF
189 //\r
190 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
191 //\r
192 OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);\r
193\r
b5817210 194 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
bfec5efa
MK
195 ASSERT (AcpiCpuDataEx != NULL);\r
196 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
197\r
198 //\r
199 // Get MP Services Protocol\r
200 //\r
201 Status = gBS->LocateProtocol (\r
202 &gEfiMpServiceProtocolGuid,\r
203 NULL,\r
204 (VOID **)&MpServices\r
205 );\r
206 ASSERT_EFI_ERROR (Status);\r
207\r
bfec5efa
MK
208 //\r
209 // Get the number of CPUs\r
210 //\r
211 Status = MpServices->GetNumberOfProcessors (\r
212 MpServices,\r
213 &NumberOfCpus,\r
214 &NumberOfEnabledProcessors\r
215 );\r
216 ASSERT_EFI_ERROR (Status);\r
217 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
218\r
219 //\r
220 // Initialize ACPI_CPU_DATA fields\r
221 //\r
222 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
223 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
224 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
225 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
226 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
227 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
228\r
229 //\r
6eab8b43
ED
230 // Allocate stack space for all CPUs.\r
231 // Use ACPI NVS memory type because this data will be directly used by APs\r
232 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
233 // will only be used as scratch space. i.e. we won't read anything from it\r
234 // before we write to it, in PiSmmCpuDxeSmm.\r
bfec5efa 235 //\r
6eab8b43 236 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
bfec5efa
MK
237 ASSERT (Stack != NULL);\r
238 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
239\r
240 //\r
241 // Get the boot processor's GDT and IDT\r
242 //\r
243 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
244 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
245\r
246 //\r
b5817210 247 // Allocate GDT and IDT and copy current GDT and IDT contents\r
bfec5efa
MK
248 //\r
249 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
250 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
b5817210 251 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
bfec5efa
MK
252 ASSERT (Gdt != NULL);\r
253 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
254 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
255 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
256 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
257 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
258\r
8b371e93
JF
259 if (OldAcpiCpuData != NULL) {\r
260 AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
261 AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
38381e18
ED
262 AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
263 CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
8b371e93
JF
264 } else {\r
265 //\r
266 // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs\r
267 //\r
268 TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);\r
b5817210 269 RegisterTable = (CPU_REGISTER_TABLE *)AllocateZeroPages (TableSize);\r
8b371e93
JF
270 ASSERT (RegisterTable != NULL);\r
271\r
272 for (Index = 0; Index < NumberOfCpus; Index++) {\r
273 Status = MpServices->GetProcessorInfo (\r
bfec5efa
MK
274 MpServices,\r
275 Index,\r
276 &ProcessorInfoBuffer\r
277 );\r
8b371e93
JF
278 ASSERT_EFI_ERROR (Status);\r
279\r
280 RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
281 RegisterTable[Index].TableLength = 0;\r
282 RegisterTable[Index].AllocatedSize = 0;\r
283 RegisterTable[Index].RegisterTableEntry = 0;\r
284\r
285 RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;\r
286 RegisterTable[NumberOfCpus + Index].TableLength = 0;\r
287 RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;\r
288 RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;\r
289 }\r
290 AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;\r
291 AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);\r
bfec5efa 292 }\r
bfec5efa
MK
293\r
294 //\r
295 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
296 //\r
297 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
298 ASSERT_EFI_ERROR (Status);\r
299\r
300 //\r
301 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
65b24ada 302 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
bfec5efa
MK
303 //\r
304 Status = gBS->CreateEventEx (\r
305 EVT_NOTIFY_SIGNAL,\r
306 TPL_CALLBACK,\r
65b24ada
JF
307 CpuS3DataOnEndOfDxe,\r
308 AcpiCpuData,\r
bfec5efa
MK
309 &gEfiEndOfDxeEventGroupGuid,\r
310 &Event\r
311 );\r
312 ASSERT_EFI_ERROR (Status);\r
313\r
314 return EFI_SUCCESS;\r
315}\r