VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/OvmfPkg/CpuS3DataDxe/CpuS3Data.c@ 106129

Last change on this file since 106129 was 101291, checked in by vboxsync, 18 months ago

EFI/FirmwareNew: Make edk2-stable202308 build on all supported platforms (using gcc at least, msvc not tested yet), bugref:4643

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