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
8Copyright (c) 2014-2015, Red Hat, Inc.<BR>
9Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
10
11This program and the accompanying materials
12are licensed and made available under the terms and conditions
13of the BSD License which accompanies this distribution.  The
14full text of the license may be found at
15http://opensource.org/licenses/bsd-license.php
16
17THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
18WITHOUT 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
39EFI_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**/
54VOID*
55AllocateMemoryBelow4G (
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**/
92VOID *
93ScanTableInRSDT (
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**/
130VOID *
131ScanTableInXSDT (
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**/
167EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
168FindAcpiFacsFromFadt (
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**/
202EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
203FindAcpiFacsTableByAcpiGuid (
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**/
269EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
270FindAcpiFacsTable (
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**/
294EFI_PHYSICAL_ADDRESS
295S3CreateIdentityMappingPageTables (
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**/
388STATIC
389EFI_STATUS
390EFIAPI
391S3Ready (
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**/
490VOID
491EFIAPI
492OnEndOfDxe (
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**/
527EFI_STATUS
528EFIAPI
529InstallEndOfDxeCallback (
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  if (!FeaturePcdGet (PcdSmmSmramRequire)) {
542    Status = gBS->InstallMultipleProtocolInterfaces (
543                    &ImageHandle,
544                    &gEfiLockBoxProtocolGuid, NULL,
545                    NULL
546                    );
547    ASSERT_EFI_ERROR (Status);
548  }
549
550  Status = gBS->CreateEventEx (
551                  EVT_NOTIFY_SIGNAL,
552                  TPL_CALLBACK,
553                  OnEndOfDxe,
554                  NULL, /* NotifyContext */
555                  &gEfiEndOfDxeEventGroupGuid,
556                  &EndOfDxeEvent
557                  );
558  ASSERT_EFI_ERROR (Status);
559  return Status;
560}
561