]> git.proxmox.com Git - mirror_edk2.git/blame - UefiCpuPkg/CpuS3DataDxe/CpuS3Data.c
UefiCpuPkg/CpuS3DataDxe: do not allocate useless register tables
[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
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
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
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
bfec5efa 60 Status = gBS->AllocatePages (\r
6eab8b43 61 AllocateAnyPages,\r
bfec5efa
MK
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
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
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
bfec5efa
MK
98/**\r
99 Callback function executed when the EndOfDxe event group is signaled.\r
100\r
65b24ada 101 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.\r
bfec5efa
MK
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
65b24ada 108CpuS3DataOnEndOfDxe (\r
bfec5efa
MK
109 IN EFI_EVENT Event,\r
110 OUT VOID *Context\r
111 )\r
112{\r
65b24ada
JF
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
bfec5efa 129 DEBUG ((EFI_D_VERBOSE, "%a\n", __FUNCTION__));\r
65b24ada 130 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);\r
bfec5efa
MK
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
ca98f603 150 @retval EFI_UNSUPPORTED Do not support ACPI S3.\r
bfec5efa
MK
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
166 UINTN NumberOfEnabledProcessors;\r
167 VOID *Stack;\r
bfec5efa
MK
168 UINTN GdtSize;\r
169 UINTN IdtSize;\r
170 VOID *Gdt;\r
171 VOID *Idt;\r
172 EFI_EVENT Event;\r
8b371e93 173 ACPI_CPU_DATA *OldAcpiCpuData;\r
bfec5efa 174\r
ca98f603
SZ
175 if (!PcdGetBool (PcdAcpiS3Enable)) {\r
176 return EFI_UNSUPPORTED;\r
177 }\r
178\r
8b371e93
JF
179 //\r
180 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
181 //\r
182 OldAcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);\r
183\r
b5817210 184 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));\r
bfec5efa
MK
185 ASSERT (AcpiCpuDataEx != NULL);\r
186 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;\r
187\r
188 //\r
189 // Get MP Services Protocol\r
190 //\r
191 Status = gBS->LocateProtocol (\r
192 &gEfiMpServiceProtocolGuid,\r
193 NULL,\r
194 (VOID **)&MpServices\r
195 );\r
196 ASSERT_EFI_ERROR (Status);\r
197\r
bfec5efa
MK
198 //\r
199 // Get the number of CPUs\r
200 //\r
201 Status = MpServices->GetNumberOfProcessors (\r
202 MpServices,\r
203 &NumberOfCpus,\r
204 &NumberOfEnabledProcessors\r
205 );\r
206 ASSERT_EFI_ERROR (Status);\r
207 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;\r
208\r
209 //\r
210 // Initialize ACPI_CPU_DATA fields\r
211 //\r
212 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);\r
213 AcpiCpuData->ApMachineCheckHandlerBase = 0;\r
214 AcpiCpuData->ApMachineCheckHandlerSize = 0;\r
215 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;\r
216 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;\r
217 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;\r
218\r
219 //\r
6eab8b43
ED
220 // Allocate stack space for all CPUs.\r
221 // Use ACPI NVS memory type because this data will be directly used by APs\r
222 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer\r
223 // will only be used as scratch space. i.e. we won't read anything from it\r
224 // before we write to it, in PiSmmCpuDxeSmm.\r
bfec5efa 225 //\r
6eab8b43 226 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);\r
bfec5efa
MK
227 ASSERT (Stack != NULL);\r
228 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;\r
229\r
230 //\r
231 // Get the boot processor's GDT and IDT\r
232 //\r
233 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);\r
234 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);\r
235\r
236 //\r
b5817210 237 // Allocate GDT and IDT and copy current GDT and IDT contents\r
bfec5efa
MK
238 //\r
239 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;\r
240 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;\r
b5817210 241 Gdt = AllocateZeroPages (GdtSize + IdtSize);\r
bfec5efa
MK
242 ASSERT (Gdt != NULL);\r
243 Idt = (VOID *)((UINTN)Gdt + GdtSize);\r
244 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);\r
245 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);\r
246 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;\r
247 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;\r
248\r
8b371e93
JF
249 if (OldAcpiCpuData != NULL) {\r
250 AcpiCpuData->RegisterTable = OldAcpiCpuData->RegisterTable;\r
251 AcpiCpuData->PreSmmInitRegisterTable = OldAcpiCpuData->PreSmmInitRegisterTable;\r
38381e18
ED
252 AcpiCpuData->ApLocation = OldAcpiCpuData->ApLocation;\r
253 CopyMem (&AcpiCpuData->CpuStatus, &OldAcpiCpuData->CpuStatus, sizeof (CPU_STATUS_INFORMATION));\r
bfec5efa 254 }\r
bfec5efa
MK
255\r
256 //\r
257 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure\r
258 //\r
259 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);\r
260 ASSERT_EFI_ERROR (Status);\r
261\r
262 //\r
263 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
65b24ada 264 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA\r
bfec5efa
MK
265 //\r
266 Status = gBS->CreateEventEx (\r
267 EVT_NOTIFY_SIGNAL,\r
268 TPL_CALLBACK,\r
65b24ada
JF
269 CpuS3DataOnEndOfDxe,\r
270 AcpiCpuData,\r
bfec5efa
MK
271 &gEfiEndOfDxeEventGroupGuid,\r
272 &Event\r
273 );\r
274 ASSERT_EFI_ERROR (Status);\r
275\r
276 return EFI_SUCCESS;\r
277}\r