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