]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/AcpiS3SaveDxe/AcpiS3Save.c
OvmfPkg: fix conversion specifiers in DEBUG format strings
[mirror_edk2.git] / OvmfPkg / AcpiS3SaveDxe / AcpiS3Save.c
1 /** @file
2 This is a replacement for the ACPI S3 Save protocol.
3
4 The ACPI S3 Save protocol used to be defined in the S3 boot path
5 specification 0.9. Instead, the same functionality is now hooked to the
6 End-of-Dxe event.
7
8 Copyright (c) 2014-2015, Red Hat, Inc.<BR>
9 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
10
11 This program and the accompanying materials
12 are licensed and made available under the terms and conditions
13 of the BSD License which accompanies this distribution. The
14 full text of the license may be found at
15 http://opensource.org/licenses/bsd-license.php
16
17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19
20 **/
21
22 #include <PiDxe.h>
23 #include <Library/BaseLib.h>
24 #include <Library/BaseMemoryLib.h>
25 #include <Library/UefiBootServicesTableLib.h>
26 #include <Library/UefiRuntimeServicesTableLib.h>
27 #include <Library/HobLib.h>
28 #include <Library/LockBoxLib.h>
29 #include <Library/PcdLib.h>
30 #include <Library/DebugLib.h>
31 #include <Library/QemuFwCfgLib.h>
32 #include <Guid/AcpiVariableCompatibility.h>
33 #include <Guid/AcpiS3Context.h>
34 #include <Guid/Acpi.h>
35 #include <Guid/EventGroup.h>
36 #include <Protocol/LockBox.h>
37 #include <IndustryStandard/Acpi.h>
38
39 EFI_GUID mAcpiS3IdtrProfileGuid = {
40 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
41 };
42
43 /**
44 Allocate memory below 4G memory address.
45
46 This function allocates memory below 4G memory address.
47
48 @param MemoryType Memory type of memory to allocate.
49 @param Size Size of memory to allocate.
50
51 @return Allocated address for output.
52
53 **/
54 VOID*
55 AllocateMemoryBelow4G (
56 IN EFI_MEMORY_TYPE MemoryType,
57 IN UINTN Size
58 )
59 {
60 UINTN Pages;
61 EFI_PHYSICAL_ADDRESS Address;
62 EFI_STATUS Status;
63 VOID* Buffer;
64
65 Pages = EFI_SIZE_TO_PAGES (Size);
66 Address = 0xffffffff;
67
68 Status = gBS->AllocatePages (
69 AllocateMaxAddress,
70 MemoryType,
71 Pages,
72 &Address
73 );
74 ASSERT_EFI_ERROR (Status);
75
76 Buffer = (VOID *) (UINTN) Address;
77 ZeroMem (Buffer, Size);
78
79 return Buffer;
80 }
81
82 /**
83
84 This function scan ACPI table in RSDT.
85
86 @param Rsdt ACPI RSDT
87 @param Signature ACPI table signature
88
89 @return ACPI table
90
91 **/
92 VOID *
93 ScanTableInRSDT (
94 IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
95 IN UINT32 Signature
96 )
97 {
98 UINTN Index;
99 UINT32 EntryCount;
100 UINT32 *EntryPtr;
101 EFI_ACPI_DESCRIPTION_HEADER *Table;
102
103 if (Rsdt == NULL) {
104 return NULL;
105 }
106
107 EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
108
109 EntryPtr = (UINT32 *)(Rsdt + 1);
110 for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
111 Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
112 if (Table->Signature == Signature) {
113 return Table;
114 }
115 }
116
117 return NULL;
118 }
119
120 /**
121
122 This function scan ACPI table in XSDT.
123
124 @param Xsdt ACPI XSDT
125 @param Signature ACPI table signature
126
127 @return ACPI table
128
129 **/
130 VOID *
131 ScanTableInXSDT (
132 IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
133 IN UINT32 Signature
134 )
135 {
136 UINTN Index;
137 UINT32 EntryCount;
138 UINT64 EntryPtr;
139 UINTN BasePtr;
140 EFI_ACPI_DESCRIPTION_HEADER *Table;
141
142 if (Xsdt == NULL) {
143 return NULL;
144 }
145
146 EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
147
148 BasePtr = (UINTN)(Xsdt + 1);
149 for (Index = 0; Index < EntryCount; Index ++) {
150 CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
151 Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
152 if (Table->Signature == Signature) {
153 return Table;
154 }
155 }
156
157 return NULL;
158 }
159
160 /**
161 To find Facs in FADT.
162
163 @param Fadt FADT table pointer
164
165 @return Facs table pointer.
166 **/
167 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
168 FindAcpiFacsFromFadt (
169 IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt
170 )
171 {
172 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
173 UINT64 Data64;
174
175 if (Fadt == NULL) {
176 return NULL;
177 }
178
179 if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
180 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
181 } else {
182 if (Fadt->FirmwareCtrl != 0) {
183 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
184 } else {
185 CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
186 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
187 }
188 }
189 return Facs;
190 }
191
192 /**
193 To find Facs in Acpi tables.
194
195 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
196 in the table.
197
198 @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
199
200 @return Facs table pointer.
201 **/
202 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
203 FindAcpiFacsTableByAcpiGuid (
204 IN EFI_GUID *AcpiTableGuid
205 )
206 {
207 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
208 EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
209 EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
210 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
211 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
212 UINTN Index;
213
214 Rsdp = NULL;
215 //
216 // found ACPI table RSD_PTR from system table
217 //
218 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
219 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
220 //
221 // A match was found.
222 //
223 Rsdp = gST->ConfigurationTable[Index].VendorTable;
224 break;
225 }
226 }
227
228 if (Rsdp == NULL) {
229 return NULL;
230 }
231
232 //
233 // Search XSDT
234 //
235 if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
236 Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
237 Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
238 if (Fadt != NULL) {
239 Facs = FindAcpiFacsFromFadt (Fadt);
240 if (Facs != NULL) {
241 return Facs;
242 }
243 }
244 }
245
246 //
247 // Search RSDT
248 //
249 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
250 Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
251 if (Fadt != NULL) {
252 Facs = FindAcpiFacsFromFadt (Fadt);
253 if (Facs != NULL) {
254 return Facs;
255 }
256 }
257
258 return NULL;
259 }
260
261 /**
262 To find Facs in Acpi tables.
263
264 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
265 in the table.
266
267 @return Facs table pointer.
268 **/
269 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
270 FindAcpiFacsTable (
271 VOID
272 )
273 {
274 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
275
276 Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);
277 if (Facs != NULL) {
278 return Facs;
279 }
280
281 return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);
282 }
283
284 /**
285 Allocates and fills in the Page Directory and Page Table Entries to
286 establish a 1:1 Virtual to Physical mapping.
287 If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
288 virtual to physical mapping page table.
289 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
290
291 @return the 1:1 Virtual to Physical identity mapping page table base address.
292
293 **/
294 EFI_PHYSICAL_ADDRESS
295 S3CreateIdentityMappingPageTables (
296 VOID
297 )
298 {
299 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
300 UINT32 RegEax;
301 UINT32 RegEdx;
302 UINT8 PhysicalAddressBits;
303 UINT32 NumberOfPml4EntriesNeeded;
304 UINT32 NumberOfPdpEntriesNeeded;
305 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
306 UINTN TotalPageTableSize;
307 VOID *Hob;
308 BOOLEAN Page1GSupport;
309
310 Page1GSupport = FALSE;
311 if (PcdGetBool(PcdUse1GPageTable)) {
312 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
313 if (RegEax >= 0x80000001) {
314 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
315 if ((RegEdx & BIT26) != 0) {
316 Page1GSupport = TRUE;
317 }
318 }
319 }
320
321 //
322 // Get physical address bits supported.
323 //
324 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
325 if (Hob != NULL) {
326 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
327 } else {
328 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
329 if (RegEax >= 0x80000008) {
330 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
331 PhysicalAddressBits = (UINT8) RegEax;
332 } else {
333 PhysicalAddressBits = 36;
334 }
335 }
336
337 //
338 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
339 //
340 ASSERT (PhysicalAddressBits <= 52);
341 if (PhysicalAddressBits > 48) {
342 PhysicalAddressBits = 48;
343 }
344
345 //
346 // Calculate the table entries needed.
347 //
348 if (PhysicalAddressBits <= 39 ) {
349 NumberOfPml4EntriesNeeded = 1;
350 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
351 } else {
352 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
353 NumberOfPdpEntriesNeeded = 512;
354 }
355
356 //
357 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
358 //
359 if (!Page1GSupport) {
360 TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);
361 } else {
362 TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded);
363 }
364 DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %Lx pages\n",
365 (UINT64)TotalPageTableSize));
366
367 //
368 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
369 //
370 S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
371 ASSERT (S3NvsPageTableAddress != 0);
372 return S3NvsPageTableAddress;
373 } else {
374 //
375 // If DXE is running 32-bit mode, no need to establish page table.
376 //
377 return (EFI_PHYSICAL_ADDRESS) 0;
378 }
379 }
380
381 /**
382 Prepares all information that is needed in the S3 resume boot path.
383
384 Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
385
386 @retval EFI_SUCCESS All information was saved successfully.
387 **/
388 STATIC
389 EFI_STATUS
390 EFIAPI
391 S3Ready (
392 VOID
393 )
394 {
395 EFI_STATUS Status;
396 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
397 ACPI_S3_CONTEXT *AcpiS3Context;
398 STATIC BOOLEAN AlreadyEntered;
399 IA32_DESCRIPTOR *Idtr;
400 IA32_IDT_GATE_DESCRIPTOR *IdtGate;
401
402 DEBUG ((EFI_D_INFO, "S3Ready!\n"));
403
404 ASSERT (!AlreadyEntered);
405 if (AlreadyEntered) {
406 return EFI_SUCCESS;
407 }
408 AlreadyEntered = TRUE;
409
410 AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
411 ASSERT (AcpiS3Context != NULL);
412 AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
413
414 //
415 // Get ACPI Table because we will save its position to variable
416 //
417 AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable ();
418 ASSERT (AcpiS3Context->AcpiFacsTable != 0);
419
420 IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));
421 Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
422 Idtr->Base = (UINTN)IdtGate;
423 Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
424 AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
425
426 Status = SaveLockBox (
427 &mAcpiS3IdtrProfileGuid,
428 (VOID *)(UINTN)Idtr,
429 (UINTN)sizeof(IA32_DESCRIPTOR)
430 );
431 ASSERT_EFI_ERROR (Status);
432
433 Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
434 ASSERT_EFI_ERROR (Status);
435
436 //
437 // Allocate page table
438 //
439 AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables ();
440
441 //
442 // Allocate stack
443 //
444 AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
445 AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
446 ASSERT (AcpiS3Context->BootScriptStackBase != 0);
447
448 //
449 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
450 //
451 AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
452 SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
453
454 DEBUG ((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8Lx\n",
455 AcpiS3Context->AcpiFacsTable));
456 DEBUG ((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8Lx\n",
457 AcpiS3Context->IdtrProfile));
458 DEBUG ((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8Lx\n",
459 AcpiS3Context->S3NvsPageTableAddress));
460 DEBUG ((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8Lx\n",
461 AcpiS3Context->S3DebugBufferAddress));
462
463 Status = SaveLockBox (
464 &gEfiAcpiVariableGuid,
465 &AcpiS3ContextBuffer,
466 sizeof(AcpiS3ContextBuffer)
467 );
468 ASSERT_EFI_ERROR (Status);
469
470 Status = SaveLockBox (
471 &gEfiAcpiS3ContextGuid,
472 (VOID *)(UINTN)AcpiS3Context,
473 (UINTN)sizeof(*AcpiS3Context)
474 );
475 ASSERT_EFI_ERROR (Status);
476
477 Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
478 ASSERT_EFI_ERROR (Status);
479
480 return EFI_SUCCESS;
481 }
482
483 /**
484 Callback function executed when the EndOfDxe event group is signaled.
485
486 @param[in] Event Event whose notification function is being invoked.
487 @param[in] Context The pointer to the notification function's context, which
488 is implementation-dependent.
489 **/
490 VOID
491 EFIAPI
492 OnEndOfDxe (
493 IN EFI_EVENT Event,
494 IN VOID *Context
495 )
496 {
497 EFI_STATUS Status;
498
499 //
500 // Our S3Ready() function always succeeds.
501 //
502 Status = S3Ready ();
503 ASSERT_EFI_ERROR (Status);
504
505 //
506 // Close the event, deregistering the callback and freeing resources.
507 //
508 Status = gBS->CloseEvent (Event);
509 ASSERT_EFI_ERROR (Status);
510 }
511
512
513 /**
514 The Driver Entry Point.
515
516 The function is the driver Entry point that will register the End-of-Dxe
517 callback.
518
519 @param ImageHandle A handle for the image that is initializing this driver
520 @param SystemTable A pointer to the EFI system table
521
522 @retval EFI_SUCCESS: Driver initialized successfully
523 @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
524 @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
525
526 **/
527 EFI_STATUS
528 EFIAPI
529 InstallEndOfDxeCallback (
530 IN EFI_HANDLE ImageHandle,
531 IN EFI_SYSTEM_TABLE *SystemTable
532 )
533 {
534 EFI_STATUS Status;
535 EFI_EVENT EndOfDxeEvent;
536
537 if (!QemuFwCfgS3Enabled()) {
538 return EFI_LOAD_ERROR;
539 }
540
541 Status = gBS->InstallMultipleProtocolInterfaces (
542 &ImageHandle,
543 &gEfiLockBoxProtocolGuid, NULL,
544 NULL
545 );
546 ASSERT_EFI_ERROR (Status);
547
548 Status = gBS->CreateEventEx (
549 EVT_NOTIFY_SIGNAL,
550 TPL_CALLBACK,
551 OnEndOfDxe,
552 NULL, /* NotifyContext */
553 &gEfiEndOfDxeEventGroupGuid,
554 &EndOfDxeEvent
555 );
556 ASSERT_EFI_ERROR (Status);
557 return Status;
558 }