VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/CpuS3DataDxe/CpuS3Data.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 4 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1/** @file
2ACPI CPU Data initialization module
3
4This module initializes the ACPI_CPU_DATA structure and registers the address
5of this structure in the PcdCpuS3DataAddress PCD. This is a generic/simple
6version of this module. It does not provide a machine check handler or CPU
7register initialization tables for ACPI S3 resume. It also only supports the
8number of CPUs reported by the MP Services Protocol, so this module does not
9support hot plug CPUs. This module can be copied into a CPU specific package
10and customized if these additional features are required.
11
12Copyright (c) 2013 - 2024, Intel Corporation. All rights reserved.<BR>
13Copyright (c) 2015 - 2020, Red Hat, Inc.
14
15SPDX-License-Identifier: BSD-2-Clause-Patent
16
17**/
18
19#include <PiDxe.h>
20
21#include <AcpiCpuData.h>
22
23#include <Library/BaseLib.h>
24#include <Library/BaseMemoryLib.h>
25#include <Library/DebugLib.h>
26#include <Library/MemoryAllocationLib.h>
27#include <Library/MtrrLib.h>
28#include <Library/UefiBootServicesTableLib.h>
29#include <Library/LockBoxLib.h>
30
31#include <Protocol/MpService.h>
32#include <Guid/EventGroup.h>
33
34//
35// Data structure used to allocate ACPI_CPU_DATA and its supporting structures
36//
37typedef struct {
38 ACPI_CPU_DATA AcpiCpuData;
39 MTRR_SETTINGS MtrrTable;
40 IA32_DESCRIPTOR GdtrProfile;
41 IA32_DESCRIPTOR IdtrProfile;
42} ACPI_CPU_DATA_EX;
43
44/**
45 Allocate EfiACPIMemoryNVS memory.
46
47 @param[in] Size Size of memory to allocate.
48
49 @return Allocated address for output.
50
51**/
52VOID *
53AllocateAcpiNvsMemory (
54 IN UINTN Size
55 )
56{
57 EFI_PHYSICAL_ADDRESS Address;
58 EFI_STATUS Status;
59 VOID *Buffer;
60
61 Status = gBS->AllocatePages (
62 AllocateAnyPages,
63 EfiACPIMemoryNVS,
64 EFI_SIZE_TO_PAGES (Size),
65 &Address
66 );
67 if (EFI_ERROR (Status)) {
68 return NULL;
69 }
70
71 Buffer = (VOID *)(UINTN)Address;
72 ZeroMem (Buffer, Size);
73
74 return Buffer;
75}
76
77/**
78 Allocate memory and clean it with zero.
79
80 @param[in] Size Size of memory to allocate.
81
82 @return Allocated address for output.
83
84**/
85VOID *
86AllocateZeroPages (
87 IN UINTN Size
88 )
89{
90 VOID *Buffer;
91
92 Buffer = AllocatePages (EFI_SIZE_TO_PAGES (Size));
93 if (Buffer != NULL) {
94 ZeroMem (Buffer, Size);
95 }
96
97 return Buffer;
98}
99
100/**
101 Callback function executed when the EndOfDxe event group is signaled.
102
103 We delay allocating StartupVector and saving the MTRR settings until BDS signals EndOfDxe.
104
105 @param[in] Event Event whose notification function is being invoked.
106 @param[out] Context Pointer to the MTRR_SETTINGS buffer to fill in.
107**/
108VOID
109EFIAPI
110CpuS3DataOnEndOfDxe (
111 IN EFI_EVENT Event,
112 OUT VOID *Context
113 )
114{
115 EFI_STATUS Status;
116 ACPI_CPU_DATA_EX *AcpiCpuDataEx;
117
118 AcpiCpuDataEx = (ACPI_CPU_DATA_EX *)Context;
119 //
120 // Allocate a 4KB reserved page below 1MB
121 //
122 AcpiCpuDataEx->AcpiCpuData.StartupVector = BASE_1MB - 1;
123 Status = gBS->AllocatePages (
124 AllocateMaxAddress,
125 EfiReservedMemoryType,
126 1,
127 &AcpiCpuDataEx->AcpiCpuData.StartupVector
128 );
129 ASSERT_EFI_ERROR (Status);
130
131 DEBUG ((DEBUG_VERBOSE, "%a\n", __func__));
132 MtrrGetAllMtrrs (&AcpiCpuDataEx->MtrrTable);
133
134 //
135 // Save MTRR in lockbox
136 //
137 Status = SaveLockBox (
138 &gEdkiiS3MtrrSettingGuid,
139 &AcpiCpuDataEx->MtrrTable,
140 sizeof (MTRR_SETTINGS)
141 );
142 ASSERT_EFI_ERROR (Status);
143
144 //
145 // Close event, so it will not be invoked again.
146 //
147 gBS->CloseEvent (Event);
148}
149
150/**
151 The entry function of the CpuS3Data driver.
152
153 Allocate and initialize all fields of the ACPI_CPU_DATA structure except the
154 MTRR settings. Register an event notification on gEfiEndOfDxeEventGroupGuid
155 to capture the ACPI_CPU_DATA MTRR settings. The PcdCpuS3DataAddress is set
156 to the address that ACPI_CPU_DATA is allocated at.
157
158 @param[in] ImageHandle The firmware allocated handle for the EFI image.
159 @param[in] SystemTable A pointer to the EFI System Table.
160
161 @retval EFI_SUCCESS The entry point is executed successfully.
162 @retval EFI_UNSUPPORTED Do not support ACPI S3.
163 @retval other Some error occurs when executing this entry point.
164
165**/
166EFI_STATUS
167EFIAPI
168CpuS3DataInitialize (
169 IN EFI_HANDLE ImageHandle,
170 IN EFI_SYSTEM_TABLE *SystemTable
171 )
172{
173 EFI_STATUS Status;
174 ACPI_CPU_DATA_EX *AcpiCpuDataEx;
175 ACPI_CPU_DATA *AcpiCpuData;
176 EFI_MP_SERVICES_PROTOCOL *MpServices;
177 UINTN NumberOfCpus;
178 VOID *Stack;
179 UINTN GdtSize;
180 UINTN IdtSize;
181 VOID *Gdt;
182 VOID *Idt;
183 EFI_EVENT Event;
184 ACPI_CPU_DATA *OldAcpiCpuData;
185
186 if (!PcdGetBool (PcdAcpiS3Enable)) {
187 return EFI_UNSUPPORTED;
188 }
189
190 //
191 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
192 //
193 OldAcpiCpuData = (ACPI_CPU_DATA *)(UINTN)PcdGet64 (PcdCpuS3DataAddress);
194
195 AcpiCpuDataEx = AllocateZeroPages (sizeof (ACPI_CPU_DATA_EX));
196 ASSERT (AcpiCpuDataEx != NULL);
197 AcpiCpuData = &AcpiCpuDataEx->AcpiCpuData;
198
199 if (PcdGetBool (PcdQ35SmramAtDefaultSmbase)) {
200 NumberOfCpus = PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
201 } else {
202 UINTN NumberOfEnabledProcessors;
203
204 //
205 // Get MP Services Protocol
206 //
207 Status = gBS->LocateProtocol (
208 &gEfiMpServiceProtocolGuid,
209 NULL,
210 (VOID **)&MpServices
211 );
212 ASSERT_EFI_ERROR (Status);
213
214 //
215 // Get the number of CPUs
216 //
217 Status = MpServices->GetNumberOfProcessors (
218 MpServices,
219 &NumberOfCpus,
220 &NumberOfEnabledProcessors
221 );
222 ASSERT_EFI_ERROR (Status);
223 }
224
225 AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;
226
227 //
228 // Initialize ACPI_CPU_DATA fields
229 //
230 AcpiCpuData->StackSize = PcdGet32 (PcdCpuApStackSize);
231 AcpiCpuData->ApMachineCheckHandlerBase = 0;
232 AcpiCpuData->ApMachineCheckHandlerSize = 0;
233 AcpiCpuData->GdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->GdtrProfile;
234 AcpiCpuData->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->IdtrProfile;
235 AcpiCpuData->MtrrTable = (EFI_PHYSICAL_ADDRESS)(UINTN)&AcpiCpuDataEx->MtrrTable;
236
237 //
238 // Allocate stack space for all CPUs.
239 // Use ACPI NVS memory type because this data will be directly used by APs
240 // in S3 resume phase in long mode. Also during S3 resume, the stack buffer
241 // will only be used as scratch space. i.e. we won't read anything from it
242 // before we write to it, in PiSmmCpuDxeSmm.
243 //
244 Stack = AllocateAcpiNvsMemory (NumberOfCpus * AcpiCpuData->StackSize);
245 ASSERT (Stack != NULL);
246 AcpiCpuData->StackAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)Stack;
247
248 //
249 // Get the boot processor's GDT and IDT
250 //
251 AsmReadGdtr (&AcpiCpuDataEx->GdtrProfile);
252 AsmReadIdtr (&AcpiCpuDataEx->IdtrProfile);
253
254 //
255 // Allocate GDT and IDT and copy current GDT and IDT contents
256 //
257 GdtSize = AcpiCpuDataEx->GdtrProfile.Limit + 1;
258 IdtSize = AcpiCpuDataEx->IdtrProfile.Limit + 1;
259 Gdt = AllocateZeroPages (GdtSize + IdtSize);
260 ASSERT (Gdt != NULL);
261 Idt = (VOID *)((UINTN)Gdt + GdtSize);
262 CopyMem (Gdt, (VOID *)AcpiCpuDataEx->GdtrProfile.Base, GdtSize);
263 CopyMem (Idt, (VOID *)AcpiCpuDataEx->IdtrProfile.Base, IdtSize);
264 AcpiCpuDataEx->GdtrProfile.Base = (UINTN)Gdt;
265 AcpiCpuDataEx->IdtrProfile.Base = (UINTN)Idt;
266
267 if (OldAcpiCpuData != NULL) {
268 CopyMem (&AcpiCpuData->CpuFeatureInitData, &OldAcpiCpuData->CpuFeatureInitData, sizeof (CPU_FEATURE_INIT_DATA));
269 }
270
271 //
272 // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
273 //
274 Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
275 ASSERT_EFI_ERROR (Status);
276
277 //
278 // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
279 // The notification function allocates StartupVector and saves MTRRs for ACPI_CPU_DATA
280 //
281 Status = gBS->CreateEventEx (
282 EVT_NOTIFY_SIGNAL,
283 TPL_CALLBACK,
284 CpuS3DataOnEndOfDxe,
285 AcpiCpuData,
286 &gEfiEndOfDxeEventGroupGuid,
287 &Event
288 );
289 ASSERT_EFI_ERROR (Status);
290
291 return EFI_SUCCESS;
292}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette