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