113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/** @file
213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  This is an implementation of the ACPI S3 Save protocol.  This is defined in
313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  S3 boot path specification 0.9.
413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
5353f5ba92f9420266bbf5dd86c3faae35db6a478Star ZengCopyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenThis program and the accompanying materials
813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenare licensed and made available under the terms and conditions
913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenof the BSD License which accompanies this distribution.  The
1013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenfull text of the license may be found at
1113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenhttp://opensource.org/licenses/bsd-license.php
1213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
1313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenTHE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
1413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenWITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
1513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
1613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
1713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
1813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <PiDxe.h>
1913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/BaseLib.h>
2013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/BaseMemoryLib.h>
2113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/UefiBootServicesTableLib.h>
2213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/UefiRuntimeServicesTableLib.h>
23c56b65665de7a665e29107ee9c377c1e2e84d343jyao#include <Library/HobLib.h>
2413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/LockBoxLib.h>
2513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/PcdLib.h>
2613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Library/DebugLib.h>
2713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Guid/AcpiVariableCompatibility.h>
2813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Guid/AcpiS3Context.h>
2913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Guid/Acpi.h>
3013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <Protocol/AcpiS3Save.h>
3113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include <IndustryStandard/Acpi.h>
3213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
3313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten#include "AcpiS3Save.h"
3413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
35353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng//
36353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng// 8 extra pages for PF handler.
37353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng//
38353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng#define EXTRA_PAGE_TABLE_PAGES   8
39353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
4013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
4113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
4213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
4313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenVOID
4413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenInstallAcpiS3SaveThunk (
4513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  VOID
4613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  );
4713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
4813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
4913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Hook point for AcpiVariableThunkPlatform for S3Ready.
5013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
5113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param AcpiS3Context   ACPI s3 context
5213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
5313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenVOID
5413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenS3ReadyThunkPlatform (
5513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN ACPI_S3_CONTEXT      *AcpiS3Context
5613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  );
5713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
5813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenUINTN     mLegacyRegionSize;
5913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
6013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_ACPI_S3_SAVE_PROTOCOL mS3Save = {
6113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  LegacyGetS3MemorySize,
6213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  S3Ready,
6313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten};
6413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
6513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_GUID              mAcpiS3IdtrProfileGuid = {
66ce68d3bc68eda5ce919b90aea8db094ed4b64c34lzeng  0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
6713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten};
6813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
6913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
70091249f49723fa773d17c910d2dbbc2de211466elzeng  Allocate memory below 4G memory address.
7113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
72091249f49723fa773d17c910d2dbbc2de211466elzeng  This function allocates memory below 4G memory address.
7313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
74091249f49723fa773d17c910d2dbbc2de211466elzeng  @param  MemoryType   Memory type of memory to allocate.
7513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param  Size         Size of memory to allocate.
7613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
7713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @return Allocated address for output.
7813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
7913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
8013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenVOID*
81091249f49723fa773d17c910d2dbbc2de211466elzengAllocateMemoryBelow4G (
8273f0127f98adec4beb5f235face3a515e380cfb7lzeng  IN EFI_MEMORY_TYPE    MemoryType,
8373f0127f98adec4beb5f235face3a515e380cfb7lzeng  IN UINTN              Size
8413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
8513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
8613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  UINTN                 Pages;
8713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_PHYSICAL_ADDRESS  Address;
8813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_STATUS            Status;
8913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  VOID*                 Buffer;
9013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
9113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Pages = EFI_SIZE_TO_PAGES (Size);
9213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Address = 0xffffffff;
9313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
9413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status  = gBS->AllocatePages (
9513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                   AllocateMaxAddress,
96091249f49723fa773d17c910d2dbbc2de211466elzeng                   MemoryType,
9713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                   Pages,
9813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                   &Address
9913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                   );
10013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
10113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
10213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Buffer = (VOID *) (UINTN) Address;
10313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ZeroMem (Buffer, Size);
10413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
10513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  return Buffer;
10613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
10713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
10813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
109c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
110c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  This function scan ACPI table in RSDT.
111c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
112c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @param Rsdt      ACPI RSDT
113c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @param Signature ACPI table signature
114c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
115c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @return ACPI table
116c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
117c93776c2d47b23b5e64691753efc7ab47ba257c0jyao**/
118c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoVOID *
119c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoScanTableInRSDT (
120c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  IN EFI_ACPI_DESCRIPTION_HEADER    *Rsdt,
121c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  IN UINT32                         Signature
122c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  )
123c93776c2d47b23b5e64691753efc7ab47ba257c0jyao{
124c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINTN                              Index;
125c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINT32                             EntryCount;
126c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINT32                             *EntryPtr;
127c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EFI_ACPI_DESCRIPTION_HEADER        *Table;
128c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
129c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Rsdt == NULL) {
130c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    return NULL;
131c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
132c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
133c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
134c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
135c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EntryPtr = (UINT32 *)(Rsdt + 1);
136c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
137c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
138c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    if (Table->Signature == Signature) {
139c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      return Table;
140c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    }
141c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
142c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
143c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  return NULL;
144c93776c2d47b23b5e64691753efc7ab47ba257c0jyao}
145c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
146c93776c2d47b23b5e64691753efc7ab47ba257c0jyao/**
147c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
148c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  This function scan ACPI table in XSDT.
149c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
150c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @param Xsdt      ACPI XSDT
151c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @param Signature ACPI table signature
152c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
153c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @return ACPI table
154c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
155c93776c2d47b23b5e64691753efc7ab47ba257c0jyao**/
156c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoVOID *
157c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoScanTableInXSDT (
158c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  IN EFI_ACPI_DESCRIPTION_HEADER    *Xsdt,
159c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  IN UINT32                         Signature
160c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  )
161c93776c2d47b23b5e64691753efc7ab47ba257c0jyao{
162c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINTN                          Index;
163c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINT32                         EntryCount;
164c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINT64                         EntryPtr;
165c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINTN                          BasePtr;
166c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EFI_ACPI_DESCRIPTION_HEADER    *Table;
167c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
168c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Xsdt == NULL) {
169c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    return NULL;
170c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
171c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
172c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
173c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
174c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  BasePtr = (UINTN)(Xsdt + 1);
175c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  for (Index = 0; Index < EntryCount; Index ++) {
176c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
177c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
178c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    if (Table->Signature == Signature) {
179c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      return Table;
180c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    }
181c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
182c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
183c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  return NULL;
184c93776c2d47b23b5e64691753efc7ab47ba257c0jyao}
185c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
186c93776c2d47b23b5e64691753efc7ab47ba257c0jyao/**
187c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  To find Facs in FADT.
188c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
189c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @param Fadt   FADT table pointer
190c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
191c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  @return  Facs table pointer.
192c93776c2d47b23b5e64691753efc7ab47ba257c0jyao**/
193c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoEFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
194c93776c2d47b23b5e64691753efc7ab47ba257c0jyaoFindAcpiFacsFromFadt (
195c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt
196c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  )
197c93776c2d47b23b5e64691753efc7ab47ba257c0jyao{
198c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
199c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  UINT64                                        Data64;
200c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
201c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Fadt == NULL) {
202c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    return NULL;
203c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
204c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
205c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
206c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
207c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  } else {
208c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    if (Fadt->FirmwareCtrl != 0) {
209c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
210c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    } else {
211c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
212c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
213c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    }
214c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  }
215c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  return Facs;
216c93776c2d47b23b5e64691753efc7ab47ba257c0jyao}
217c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
218c93776c2d47b23b5e64691753efc7ab47ba257c0jyao/**
21913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  To find Facs in Acpi tables.
22013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
22113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
22213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  in the table.
22313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
22413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param AcpiTableGuid   The guid used to find ACPI table in UEFI ConfigurationTable.
22513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
22613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @return  Facs table pointer.
22713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
22813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
22913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenFindAcpiFacsTableByAcpiGuid (
23013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN EFI_GUID  *AcpiTableGuid
23113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
23213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
23313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER  *Rsdp;
23413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_ACPI_DESCRIPTION_HEADER                   *Rsdt;
235c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  EFI_ACPI_DESCRIPTION_HEADER                   *Xsdt;
23613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE     *Fadt;
23713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
23813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  UINTN                                         Index;
239c93776c2d47b23b5e64691753efc7ab47ba257c0jyao
24013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Rsdp  = NULL;
24113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
24213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // found ACPI table RSD_PTR from system table
24313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
24413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
24513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
24613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten      //
24713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten      // A match was found.
24813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten      //
24913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten      Rsdp = gST->ConfigurationTable[Index].VendorTable;
25013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten      break;
25113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    }
25213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
25313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
25413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (Rsdp == NULL) {
25513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    return NULL;
25613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
25713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
258c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  //
259c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  // Search XSDT
260c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  //
261c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
262c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
263c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
264c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    if (Fadt != NULL) {
265c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      Facs = FindAcpiFacsFromFadt (Fadt);
266c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      if (Facs != NULL) {
267c93776c2d47b23b5e64691753efc7ab47ba257c0jyao        return Facs;
268c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      }
26913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    }
27013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
27113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
272c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  //
273c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  // Search RSDT
274c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  //
275c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
276c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
277c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  if (Fadt != NULL) {
278c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    Facs = FindAcpiFacsFromFadt (Fadt);
279c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    if (Facs != NULL) {
280c93776c2d47b23b5e64691753efc7ab47ba257c0jyao      return Facs;
281c93776c2d47b23b5e64691753efc7ab47ba257c0jyao    }
28213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
28313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
284c93776c2d47b23b5e64691753efc7ab47ba257c0jyao  return NULL;
28513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
28613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
28713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
28813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  To find Facs in Acpi tables.
28913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
29013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
29113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  in the table.
29213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
29313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @return  Facs table pointer.
29413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
29513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *
29613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenFindAcpiFacsTable (
29713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  VOID
29813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
29913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
30013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
30113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
30213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);
30313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (Facs != NULL) {
30413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    return Facs;
30513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
30613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
30713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);
30813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
30913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
31013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
311353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  The function will check if long mode waking vector is supported.
312353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
313353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  @param[in] Facs   Pointer to FACS table.
314353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
315353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  @retval TRUE   Long mode waking vector is supported.
316353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  @retval FALSE  Long mode waking vector is not supported.
317353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
318353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng**/
319353f5ba92f9420266bbf5dd86c3faae35db6a478Star ZengBOOLEAN
320353f5ba92f9420266bbf5dd86c3faae35db6a478Star ZengIsLongModeWakingVectorSupport (
321353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs
322353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  )
323353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng{
324353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  if ((Facs == NULL) ||
325353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ) {
326353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
327353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // Something wrong with FACS.
328353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
329353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    return FALSE;
330353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  }
331353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  if (Facs->XFirmwareWakingVector != 0) {
332353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
333353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0)) {
334353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      //
335353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      // BIOS supports 64bit waking vector.
336353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      //
337353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
338353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        return TRUE;
339353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      }
340353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
341353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  }
342353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  return FALSE;
343353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng}
344353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
345353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng/**
346353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  Allocates page table buffer.
347353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
348353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  @param[in] LongModeWakingVectorSupport    Support long mode waking vector or not.
349353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
35013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
351353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  virtual to physical mapping page table when long mode waking vector is supported, otherwise
352353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  create 4G page table when long mode waking vector is not supported and let PF handler to
353353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  handle > 4G request.
35413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
35513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
356353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  @return Page table base address.
35713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
35813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
35913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_PHYSICAL_ADDRESS
360353f5ba92f9420266bbf5dd86c3faae35db6a478Star ZengS3AllocatePageTablesBuffer (
361353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  IN BOOLEAN    LongModeWakingVectorSupport
36213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
36313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
36413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
365353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    UINTN                                         ExtraPageTablePages;
36613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    UINT32                                        RegEax;
367c56b65665de7a665e29107ee9c377c1e2e84d343jyao    UINT32                                        RegEdx;
36813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    UINT8                                         PhysicalAddressBits;
369c56b65665de7a665e29107ee9c377c1e2e84d343jyao    UINT32                                        NumberOfPml4EntriesNeeded;
370c56b65665de7a665e29107ee9c377c1e2e84d343jyao    UINT32                                        NumberOfPdpEntriesNeeded;
37113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    EFI_PHYSICAL_ADDRESS                          S3NvsPageTableAddress;
37213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    UINTN                                         TotalPageTableSize;
373c56b65665de7a665e29107ee9c377c1e2e84d343jyao    VOID                                          *Hob;
374c56b65665de7a665e29107ee9c377c1e2e84d343jyao    BOOLEAN                                       Page1GSupport;
375c56b65665de7a665e29107ee9c377c1e2e84d343jyao
376353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    Page1GSupport = FALSE;
377353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (PcdGetBool(PcdUse1GPageTable)) {
378353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
379353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      if (RegEax >= 0x80000001) {
380353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
381353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        if ((RegEdx & BIT26) != 0) {
382353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng          Page1GSupport = TRUE;
383378175d2584ab0d52922308f6a18e710a36152efjyao        }
384c56b65665de7a665e29107ee9c377c1e2e84d343jyao      }
385353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
386353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
387353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
388353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // Get physical address bits supported.
389353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
390353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
391353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (Hob != NULL) {
392353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
393353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    } else {
394353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
395353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      if (RegEax >= 0x80000008) {
396353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
397353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        PhysicalAddressBits = (UINT8) RegEax;
398ac790db940b6cc5205073e1c8cc9c3f1c01615d4Elvin Li      } else {
399353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng        PhysicalAddressBits = 36;
400ac790db940b6cc5205073e1c8cc9c3f1c01615d4Elvin Li      }
401353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
402353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
403353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
404353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
405353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
406353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    ASSERT (PhysicalAddressBits <= 52);
407353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (PhysicalAddressBits > 48) {
408353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      PhysicalAddressBits = 48;
409353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
410353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
411353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    ExtraPageTablePages = 0;
412353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (!LongModeWakingVectorSupport) {
413ac790db940b6cc5205073e1c8cc9c3f1c01615d4Elvin Li      //
414353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      // Create 4G page table when BIOS does not support long mode waking vector,
415353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      // and let PF handler to handle > 4G request.
416ac790db940b6cc5205073e1c8cc9c3f1c01615d4Elvin Li      //
417353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      PhysicalAddressBits = 32;
418353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
419353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
420353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
421353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
422353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // Calculate the table entries needed.
423353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
424353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (PhysicalAddressBits <= 39 ) {
425353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      NumberOfPml4EntriesNeeded = 1;
426353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
427353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    } else {
428353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
429353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      NumberOfPdpEntriesNeeded = 512;
43013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    }
431353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
432353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
433353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
434353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
435353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    if (!Page1GSupport) {
436353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);
437353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    } else {
438353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng      TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded);
439353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    }
440353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
441353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    TotalPageTableSize += ExtraPageTablePages;
442353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    DEBUG ((EFI_D_ERROR, "AcpiS3Save TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));
443353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng
444353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
445353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
446353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    //
447353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
448353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    ASSERT (S3NvsPageTableAddress != 0);
449353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng    return S3NvsPageTableAddress;
45013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  } else {
45113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    //
45213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    // If DXE is running 32-bit mode, no need to establish page table.
45313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    //
45413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    return  (EFI_PHYSICAL_ADDRESS) 0;
45513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
45613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
45713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
45813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
45913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Gets the buffer of legacy memory below 1 MB
46013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
46113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
46213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param This           A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
46313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param Size           The returned size of legacy memory below 1 MB.
46413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
46513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_SUCCESS           Size is successfully returned.
46613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
46713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
46813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
46913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_STATUS
47013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFIAPI
47113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenLegacyGetS3MemorySize (
47213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN  EFI_ACPI_S3_SAVE_PROTOCOL   *This,
47313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  OUT UINTN                       *Size
47413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
47513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
47613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (Size == NULL) {
47713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    return EFI_INVALID_PARAMETER;
47813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
47913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
48013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  *Size = mLegacyRegionSize;
48113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  return EFI_SUCCESS;
48213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
48313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
48413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
48513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Prepares all information that is needed in the S3 resume boot path.
48613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
48713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
48813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
48913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param This                 A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
49013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param LegacyMemoryAddress  The base address of legacy memory.
49113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
49213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_NOT_FOUND         Some necessary information cannot be found.
49313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_SUCCESS           All information was saved successfully.
49413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_OUT_OF_RESOURCES  Resources were insufficient to save all the information.
49513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
49613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
49713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
49813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_STATUS
49913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFIAPI
50013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenS3Ready (
50113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN EFI_ACPI_S3_SAVE_PROTOCOL    *This,
50213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN VOID                         *LegacyMemoryAddress
50313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
50413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
50513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_STATUS                                    Status;
50613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_PHYSICAL_ADDRESS                          AcpiS3ContextBuffer;
50713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ACPI_S3_CONTEXT                               *AcpiS3Context;
50813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  STATIC BOOLEAN                                AlreadyEntered;
50913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IA32_DESCRIPTOR                               *Idtr;
51013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IA32_IDT_GATE_DESCRIPTOR                      *IdtGate;
511353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
51213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
51313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  DEBUG ((EFI_D_INFO, "S3Ready!\n"));
51413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
51513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
51613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
51713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // So if 2nd S3Save() is triggered later, we need ignore it.
51813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
51913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (AlreadyEntered) {
52013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    return EFI_SUCCESS;
52113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
52213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  AlreadyEntered = TRUE;
52313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
524091249f49723fa773d17c910d2dbbc2de211466elzeng  AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
52513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT (AcpiS3Context != NULL);
52613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
52713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
52813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
52913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // Get ACPI Table because we will save its position to variable
53013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
531353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) FindAcpiFacsTable ();
532353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS) (UINTN) Facs;
53313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT (AcpiS3Context->AcpiFacsTable != 0);
53413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
535091249f49723fa773d17c910d2dbbc2de211466elzeng  IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));
53613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
53713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Idtr->Base  = (UINTN)IdtGate;
53813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
53913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
54013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
54113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = SaveLockBox (
54213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             &mAcpiS3IdtrProfileGuid,
54313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             (VOID *)(UINTN)Idtr,
54413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             (UINTN)sizeof(IA32_DESCRIPTOR)
54513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             );
54613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
54713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
54813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
54913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
55013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
55113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
55213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // Allocate page table
55313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
554353f5ba92f9420266bbf5dd86c3faae35db6a478Star Zeng  AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));
55513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
55613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
55713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  // Allocate stack
55813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
55913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
560091249f49723fa773d17c910d2dbbc2de211466elzeng  AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
56113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT (AcpiS3Context->BootScriptStackBase != 0);
56213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
56313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
564f4a25e813f7ffa624b4868eb19fe13a34c4778cevanjeff  // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
56513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  //
566091249f49723fa773d17c910d2dbbc2de211466elzeng  AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
567f4a25e813f7ffa624b4868eb19fe13a34c4778cevanjeff  SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
56813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
56913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));
57013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));
57113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));
57213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));
573b34039b2e17e682d78feb92afba20132cc7d1e0bGao, Liming  DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));
574b34039b2e17e682d78feb92afba20132cc7d1e0bGao, Liming  DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));
57513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
57613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = SaveLockBox (
57713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             &gEfiAcpiVariableGuid,
57813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             &AcpiS3ContextBuffer,
57913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             sizeof(AcpiS3ContextBuffer)
58013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             );
58113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
58213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
58313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = SaveLockBox (
58413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             &gEfiAcpiS3ContextGuid,
58513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             (VOID *)(UINTN)AcpiS3Context,
58613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             (UINTN)sizeof(*AcpiS3Context)
58713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten             );
58813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
58913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
59013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
59113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
59213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
59313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
59413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    S3ReadyThunkPlatform (AcpiS3Context);
59513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
59613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
59713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  return EFI_SUCCESS;
59813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
59913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
60013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten/**
60113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  The Driver Entry Point.
60213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
60313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  The function is the driver Entry point which will produce AcpiS3SaveProtocol.
60413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
60513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param ImageHandle   A handle for the image that is initializing this driver
60613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @param SystemTable   A pointer to the EFI system table
60713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
60813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_SUCCESS:              Driver initialized successfully
60913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_LOAD_ERROR:           Failed to Initialize or has been loaded
61013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  @retval EFI_OUT_OF_RESOURCES      Could not allocate needed resources
61113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
61213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten**/
61313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFI_STATUS
61413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenEFIAPI
61513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljustenInstallAcpiS3Save (
61613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN EFI_HANDLE           ImageHandle,
61713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  IN EFI_SYSTEM_TABLE     *SystemTable
61813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  )
61913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten{
62013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  EFI_STATUS        Status;
62113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
62213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (!FeaturePcdGet(PcdPlatformCsmSupport)) {
62313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    //
62413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    // More memory for no CSM tip, because GDT need relocation
62513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    //
62613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    mLegacyRegionSize = 0x250;
62713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  } else {
62813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    mLegacyRegionSize = 0x100;
62913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
63013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
63113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
63213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten    InstallAcpiS3SaveThunk ();
63313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  }
63413d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten
63513d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  Status = gBS->InstallProtocolInterface (
63613d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                  &ImageHandle,
63713d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                  &gEfiAcpiS3SaveProtocolGuid,
63813d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                  EFI_NATIVE_INTERFACE,
63913d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                  &mS3Save
64013d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten                  );
64113d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  ASSERT_EFI_ERROR (Status);
64213d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten  return Status;
64313d4af68f83c39993b90c0f4d251c4312a0ddc9ajljusten}
644