~ubuntu-branches/ubuntu/wily/edk2/wily

« back to all changes in this revision

Viewing changes to UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c

  • Committer: Package Import Robot
  • Author(s): Steve Langasek
  • Date: 2013-02-10 13:11:25 UTC
  • Revision ID: package-import@ubuntu.com-20130210131125-0zwkb8f8m4ecia4m
Tags: upstream-0~20121205.edae8d2d
ImportĀ upstreamĀ versionĀ 0~20121205.edae8d2d

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
  This module produces the EFI_PEI_S3_RESUME_PPI.
 
3
  This module works with StandAloneBootScriptExecutor to S3 resume to OS.
 
4
  This module will excute the boot script saved during last boot and after that,
 
5
  control is passed to OS waking up handler.
 
6
 
 
7
  Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
 
8
 
 
9
  This program and the accompanying materials
 
10
  are licensed and made available under the terms and conditions
 
11
  of the BSD License which accompanies this distribution.  The
 
12
  full text of the license may be found at
 
13
  http://opensource.org/licenses/bsd-license.php
 
14
 
 
15
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 
16
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 
17
 
 
18
**/
 
19
 
 
20
#include <PiPei.h>
 
21
 
 
22
#include <Guid/AcpiS3Context.h>
 
23
#include <Guid/BootScriptExecutorVariable.h>
 
24
#include <Guid/Performance.h>
 
25
#include <Ppi/ReadOnlyVariable2.h>
 
26
#include <Ppi/S3Resume2.h>
 
27
#include <Ppi/SmmAccess.h>
 
28
#include <Ppi/PostBootScriptTable.h>
 
29
#include <Ppi/EndOfPeiPhase.h>
 
30
 
 
31
#include <Library/DebugLib.h>
 
32
#include <Library/BaseLib.h>
 
33
#include <Library/TimerLib.h>
 
34
#include <Library/PeimEntryPoint.h>
 
35
#include <Library/PeiServicesLib.h>
 
36
#include <Library/HobLib.h>
 
37
#include <Library/PerformanceLib.h>
 
38
#include <Library/PeiServicesTablePointerLib.h>
 
39
#include <Library/IoLib.h>
 
40
#include <Library/BaseMemoryLib.h>
 
41
#include <Library/MemoryAllocationLib.h>
 
42
#include <Library/PcdLib.h>
 
43
#include <Library/DebugAgentLib.h>
 
44
#include <Library/LocalApicLib.h>
 
45
#include <Library/ReportStatusCodeLib.h>
 
46
#include <Library/PrintLib.h>
 
47
#include <Library/HobLib.h>
 
48
#include <Library/LockBoxLib.h>
 
49
#include <IndustryStandard/Acpi.h>
 
50
 
 
51
#pragma pack(1)
 
52
typedef union {
 
53
  struct {
 
54
    UINT32  LimitLow    : 16;
 
55
    UINT32  BaseLow     : 16;
 
56
    UINT32  BaseMid     : 8;
 
57
    UINT32  Type        : 4;
 
58
    UINT32  System      : 1;
 
59
    UINT32  Dpl         : 2;
 
60
    UINT32  Present     : 1;
 
61
    UINT32  LimitHigh   : 4;
 
62
    UINT32  Software    : 1;
 
63
    UINT32  Reserved    : 1;
 
64
    UINT32  DefaultSize : 1;
 
65
    UINT32  Granularity : 1;
 
66
    UINT32  BaseHigh    : 8;
 
67
  } Bits;
 
68
  UINT64  Uint64;
 
69
} IA32_GDT;
 
70
 
 
71
//
 
72
// Page-Map Level-4 Offset (PML4) and
 
73
// Page-Directory-Pointer Offset (PDPE) entries 4K & 2MB
 
74
//
 
75
typedef union {
 
76
  struct {
 
77
    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
 
78
    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
 
79
    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
 
80
    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
 
81
    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
 
82
    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
 
83
    UINT64  Reserved:1;               // Reserved
 
84
    UINT64  MustBeZero:2;             // Must Be Zero
 
85
    UINT64  Available:3;              // Available for use by system software
 
86
    UINT64  PageTableBaseAddress:40;  // Page Table Base Address
 
87
    UINT64  AvabilableHigh:11;        // Available for use by system software
 
88
    UINT64  Nx:1;                     // No Execute bit
 
89
  } Bits;
 
90
  UINT64    Uint64;
 
91
} PAGE_MAP_AND_DIRECTORY_POINTER;
 
92
 
 
93
//
 
94
// Page Table Entry 2MB
 
95
//
 
96
typedef union {
 
97
  struct {
 
98
    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
 
99
    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
 
100
    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
 
101
    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
 
102
    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
 
103
    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
 
104
    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
 
105
    UINT64  MustBe1:1;                // Must be 1 
 
106
    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
 
107
    UINT64  Available:3;              // Available for use by system software
 
108
    UINT64  PAT:1;                    //
 
109
    UINT64  MustBeZero:8;             // Must be zero;
 
110
    UINT64  PageTableBaseAddress:31;  // Page Table Base Address
 
111
    UINT64  AvabilableHigh:11;        // Available for use by system software
 
112
    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
 
113
  } Bits;
 
114
  UINT64    Uint64;
 
115
} PAGE_TABLE_ENTRY;
 
116
 
 
117
//
 
118
// Page Table Entry 1GB
 
119
//
 
120
typedef union {
 
121
  struct {
 
122
    UINT64  Present:1;                // 0 = Not present in memory, 1 = Present in memory
 
123
    UINT64  ReadWrite:1;              // 0 = Read-Only, 1= Read/Write
 
124
    UINT64  UserSupervisor:1;         // 0 = Supervisor, 1=User
 
125
    UINT64  WriteThrough:1;           // 0 = Write-Back caching, 1=Write-Through caching
 
126
    UINT64  CacheDisabled:1;          // 0 = Cached, 1=Non-Cached
 
127
    UINT64  Accessed:1;               // 0 = Not accessed, 1 = Accessed (set by CPU)
 
128
    UINT64  Dirty:1;                  // 0 = Not Dirty, 1 = written by processor on access to page
 
129
    UINT64  MustBe1:1;                // Must be 1 
 
130
    UINT64  Global:1;                 // 0 = Not global page, 1 = global page TLB not cleared on CR3 write
 
131
    UINT64  Available:3;              // Available for use by system software
 
132
    UINT64  PAT:1;                    //
 
133
    UINT64  MustBeZero:17;            // Must be zero;
 
134
    UINT64  PageTableBaseAddress:22;  // Page Table Base Address
 
135
    UINT64  AvabilableHigh:11;        // Available for use by system software
 
136
    UINT64  Nx:1;                     // 0 = Execute Code, 1 = No Code Execution
 
137
  } Bits;
 
138
  UINT64    Uint64;
 
139
} PAGE_TABLE_1G_ENTRY;
 
140
 
 
141
#pragma pack()
 
142
 
 
143
//
 
144
// Function prototypes
 
145
//
 
146
/**
 
147
  a ASM function to transfer control to OS.
 
148
  
 
149
  @param  S3WakingVector  The S3 waking up vector saved in ACPI Facs table
 
150
  @param  AcpiLowMemoryBase a buffer under 1M which could be used during the transfer             
 
151
**/
 
152
typedef
 
153
VOID
 
154
(EFIAPI *ASM_TRANSFER_CONTROL) (
 
155
  IN   UINT32           S3WakingVector,
 
156
  IN   UINT32           AcpiLowMemoryBase
 
157
  );
 
158
 
 
159
/**
 
160
  Restores the platform to its preboot configuration for an S3 resume and
 
161
  jumps to the OS waking vector.
 
162
 
 
163
  This function will restore the platform to its pre-boot configuration that was
 
164
  pre-stored in the boot script table and transfer control to OS waking vector.
 
165
  Upon invocation, this function is responsible for locating the following
 
166
  information before jumping to OS waking vector:
 
167
    - ACPI tables
 
168
    - boot script table
 
169
    - any other information that it needs
 
170
 
 
171
  The S3RestoreConfig() function then executes the pre-stored boot script table
 
172
  and transitions the platform to the pre-boot state. The boot script is recorded
 
173
  during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
 
174
  EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions.  Finally, this function
 
175
  transfers control to the OS waking vector. If the OS supports only a real-mode
 
176
  waking vector, this function will switch from flat mode to real mode before
 
177
  jumping to the waking vector.  If all platform pre-boot configurations are
 
178
  successfully restored and all other necessary information is ready, this
 
179
  function will never return and instead will directly jump to the OS waking
 
180
  vector. If this function returns, it indicates that the attempt to resume
 
181
  from the ACPI S3 sleep state failed.
 
182
 
 
183
  @param[in] This         Pointer to this instance of the PEI_S3_RESUME_PPI
 
184
 
 
185
  @retval EFI_ABORTED     Execution of the S3 resume boot script table failed.
 
186
  @retval EFI_NOT_FOUND   Some necessary information that is used for the S3
 
187
                          resume boot path could not be located.
 
188
 
 
189
**/
 
190
EFI_STATUS
 
191
EFIAPI
 
192
S3RestoreConfig2 (
 
193
  IN EFI_PEI_S3_RESUME2_PPI  *This
 
194
  );
 
195
 
 
196
/**
 
197
  Set data segment selectors value including DS/ES/FS/GS/SS.
 
198
 
 
199
  @param[in]  SelectorValue      Segment selector value to be set.
 
200
 
 
201
**/
 
202
VOID
 
203
EFIAPI
 
204
AsmSetDataSelectors (
 
205
  IN UINT16   SelectorValue
 
206
  );
 
207
 
 
208
//
 
209
// Globals
 
210
//
 
211
EFI_PEI_S3_RESUME2_PPI      mS3ResumePpi = { S3RestoreConfig2 };
 
212
 
 
213
EFI_PEI_PPI_DESCRIPTOR mPpiList = {
 
214
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 
215
  &gEfiPeiS3Resume2PpiGuid,
 
216
  &mS3ResumePpi
 
217
};
 
218
 
 
219
EFI_PEI_PPI_DESCRIPTOR mPpiListPostScriptTable = {
 
220
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 
221
  &gPeiPostScriptTablePpiGuid,
 
222
  0
 
223
};
 
224
 
 
225
EFI_PEI_PPI_DESCRIPTOR mPpiListEndOfPeiTable = {
 
226
  (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
 
227
  &gEfiEndOfPeiSignalPpiGuid,
 
228
  0
 
229
};
 
230
 
 
231
//
 
232
// Global Descriptor Table (GDT)
 
233
//
 
234
GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT mGdtEntries[] = {
 
235
/* selector { Global Segment Descriptor                              } */
 
236
/* 0x00 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
 
237
/* 0x08 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
 
238
/* 0x10 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}},
 
239
/* 0x18 */  {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 1,  1,  0}},
 
240
/* 0x20 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
 
241
/* 0x28 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  0, 0,  1,  0}},
 
242
/* 0x30 */  {{0xFFFF, 0,  0,  0x3,  1,  0,  1,  0xF,  0,  0, 0,  1,  0}},
 
243
/* 0x38 */  {{0xFFFF, 0,  0,  0xB,  1,  0,  1,  0xF,  0,  1, 0,  1,  0}},
 
244
/* 0x40 */  {{0,      0,  0,  0,    0,  0,  0,  0,    0,  0, 0,  0,  0}},
 
245
};
 
246
 
 
247
#define DATA_SEGEMENT_SELECTOR        0x18
 
248
 
 
249
//
 
250
// IA32 Gdt register
 
251
//
 
252
GLOBAL_REMOVE_IF_UNREFERENCED CONST IA32_DESCRIPTOR mGdt = {
 
253
  sizeof (mGdtEntries) - 1,
 
254
  (UINTN) mGdtEntries
 
255
  };
 
256
 
 
257
/**
 
258
  Performance measure function to get S3 detailed performance data.
 
259
 
 
260
  This function will getS3 detailed performance data and saved in pre-reserved ACPI memory.
 
261
**/
 
262
VOID
 
263
WriteToOsS3PerformanceData (
 
264
  VOID
 
265
  )
 
266
{
 
267
  EFI_STATUS                                    Status;
 
268
  EFI_PHYSICAL_ADDRESS                          mAcpiLowMemoryBase;
 
269
  PERF_HEADER                                   *PerfHeader;
 
270
  PERF_DATA                                     *PerfData;
 
271
  UINT64                                        Ticker;
 
272
  UINTN                                         Index;
 
273
  EFI_PEI_READ_ONLY_VARIABLE2_PPI               *VariableServices;
 
274
  UINTN                                         VarSize;
 
275
  UINTN                                         LogEntryKey;
 
276
  CONST VOID                                    *Handle;
 
277
  CONST CHAR8                                   *Token;
 
278
  CONST CHAR8                                   *Module;
 
279
  UINT64                                        StartTicker;
 
280
  UINT64                                        EndTicker;
 
281
  UINT64                                        StartValue;
 
282
  UINT64                                        EndValue;
 
283
  BOOLEAN                                       CountUp;
 
284
  UINT64                                        Freq;
 
285
 
 
286
  //
 
287
  // Retrive time stamp count as early as possilbe
 
288
  //
 
289
  Ticker = GetPerformanceCounter ();
 
290
 
 
291
  Freq   = GetPerformanceCounterProperties (&StartValue, &EndValue);
 
292
 
 
293
  Freq   = DivU64x32 (Freq, 1000);
 
294
 
 
295
  Status = PeiServicesLocatePpi (
 
296
             &gEfiPeiReadOnlyVariable2PpiGuid,
 
297
             0,
 
298
             NULL,
 
299
             (VOID **) &VariableServices
 
300
             );
 
301
  if (EFI_ERROR (Status)) {
 
302
    return;
 
303
  }
 
304
 
 
305
  VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);
 
306
  Status = VariableServices->GetVariable (
 
307
                               VariableServices,
 
308
                               L"PerfDataMemAddr",
 
309
                               &gPerformanceProtocolGuid,
 
310
                               NULL,
 
311
                               &VarSize,
 
312
                               &mAcpiLowMemoryBase
 
313
                               );
 
314
  if (EFI_ERROR (Status)) {
 
315
    DEBUG ((EFI_D_ERROR, "Fail to retrieve variable to log S3 performance data \n"));
 
316
    return;
 
317
  }
 
318
 
 
319
  PerfHeader = (PERF_HEADER *) (UINTN) mAcpiLowMemoryBase;
 
320
 
 
321
  if (PerfHeader->Signiture != PERFORMANCE_SIGNATURE) {
 
322
    DEBUG ((EFI_D_ERROR, "Performance data in ACPI memory get corrupted! \n"));
 
323
    return;
 
324
  }
 
325
 
 
326
  //
 
327
  // Record total S3 resume time.
 
328
  //
 
329
  if (EndValue >= StartValue) {
 
330
    PerfHeader->S3Resume = Ticker - StartValue;
 
331
    CountUp              = TRUE;
 
332
  } else {
 
333
    PerfHeader->S3Resume = StartValue - Ticker;
 
334
    CountUp              = FALSE;
 
335
  }
 
336
 
 
337
  //
 
338
  // Get S3 detailed performance data
 
339
  //
 
340
  Index = 0;
 
341
  LogEntryKey = 0;
 
342
  while ((LogEntryKey = GetPerformanceMeasurement (
 
343
                          LogEntryKey,
 
344
                          &Handle,
 
345
                          &Token,
 
346
                          &Module,
 
347
                          &StartTicker,
 
348
                          &EndTicker)) != 0) {
 
349
    if (EndTicker != 0) {
 
350
      PerfData = &PerfHeader->S3Entry[Index];
 
351
 
 
352
      //
 
353
      // Use File Handle to specify the different performance log for PEIM.
 
354
      // File Handle is the base address of PEIM FFS file.
 
355
      //
 
356
      if ((AsciiStrnCmp (Token, "PEIM", PEI_PERFORMANCE_STRING_SIZE) == 0) && (Handle != NULL)) {
 
357
        AsciiSPrint (PerfData->Token, PERF_TOKEN_LENGTH, "0x%11p", Handle);
 
358
      } else {
 
359
        AsciiStrnCpy (PerfData->Token, Token, PERF_TOKEN_LENGTH);
 
360
      }
 
361
      if (StartTicker == 1) {
 
362
        StartTicker = StartValue;
 
363
      }
 
364
      if (EndTicker == 1) {
 
365
        EndTicker = StartValue;
 
366
      }
 
367
      Ticker = CountUp? (EndTicker - StartTicker) : (StartTicker - EndTicker);
 
368
      PerfData->Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
 
369
 
 
370
      //
 
371
      // Only Record > 1ms performance data so that more big performance can be recorded.
 
372
      //
 
373
      if ((Ticker > Freq) && (++Index >= PERF_PEI_ENTRY_MAX_NUM)) {
 
374
        //
 
375
        // Reach the maximum number of PEI performance log entries.
 
376
        //
 
377
        break;
 
378
      }
 
379
    }
 
380
  }
 
381
  PerfHeader->S3EntryNum = (UINT32) Index;
 
382
}
 
383
 
 
384
/**
 
385
  The function will check if current waking vector is long mode.
 
386
 
 
387
  @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
 
388
 
 
389
  @retval TRUE   Current context need long mode waking vector.
 
390
  @retval FALSE  Current context need not long mode waking vector.
 
391
**/
 
392
BOOLEAN
 
393
IsLongModeWakingVector (
 
394
  IN ACPI_S3_CONTEXT                *AcpiS3Context
 
395
  )
 
396
{
 
397
  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
 
398
 
 
399
  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
 
400
  if ((Facs == NULL) ||
 
401
      (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
 
402
      ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
 
403
    // Something wrong with FACS
 
404
    return FALSE;
 
405
  }
 
406
  if (Facs->XFirmwareWakingVector != 0) {
 
407
    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
 
408
        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
 
409
        ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
 
410
      // Both BIOS and OS wants 64bit vector
 
411
      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
412
        return TRUE;
 
413
      }
 
414
    }
 
415
  }
 
416
  return FALSE;
 
417
}
 
418
 
 
419
/**
 
420
  Jump to OS waking vector.
 
421
  The function will install boot script done PPI, report S3 resume status code, and then jump to OS waking vector.
 
422
 
 
423
  @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
 
424
  @param  PeiS3ResumeState              a pointer to a structure of PEI_S3_RESUME_STATE
 
425
**/
 
426
VOID
 
427
EFIAPI
 
428
S3ResumeBootOs (
 
429
  IN ACPI_S3_CONTEXT                *AcpiS3Context,
 
430
  IN PEI_S3_RESUME_STATE            *PeiS3ResumeState
 
431
  )
 
432
{
 
433
  EFI_STATUS                                    Status;
 
434
  EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;
 
435
  ASM_TRANSFER_CONTROL                          AsmTransferControl;
 
436
  UINTN                                         TempStackTop;
 
437
  UINTN                                         TempStack[0x10];
 
438
 
 
439
  //
 
440
  // Restore IDT
 
441
  //
 
442
  AsmWriteIdtr (&PeiS3ResumeState->Idtr);
 
443
 
 
444
  if (PeiS3ResumeState->ReturnStatus != EFI_SUCCESS) {
 
445
    //
 
446
    // Report Status code that boot script execution is failed
 
447
    //
 
448
    REPORT_STATUS_CODE (
 
449
      EFI_ERROR_CODE | EFI_ERROR_MINOR,
 
450
      (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_BOOT_SCRIPT_ERROR)
 
451
      );
 
452
  }
 
453
 
 
454
  //
 
455
  // NOTE: Because Debug Timer interrupt and system interrupts will be disabled 
 
456
  // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted
 
457
  // by soft debugger.
 
458
  //
 
459
 
 
460
  PERF_END (NULL, "ScriptExec", NULL, 0);
 
461
 
 
462
  //
 
463
  // Install BootScriptDonePpi
 
464
  //
 
465
  Status = PeiServicesInstallPpi (&mPpiListPostScriptTable);
 
466
  ASSERT_EFI_ERROR (Status);
 
467
 
 
468
  //
 
469
  // Get ACPI Table Address
 
470
  //
 
471
  Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
 
472
 
 
473
  if ((Facs == NULL) ||
 
474
      (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
 
475
      ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
 
476
    //
 
477
    // Report Status code that no valid vector is found
 
478
    //
 
479
    REPORT_STATUS_CODE (
 
480
      EFI_ERROR_CODE | EFI_ERROR_MAJOR,
 
481
      (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
 
482
      );
 
483
    CpuDeadLoop ();
 
484
    return ;
 
485
  }
 
486
 
 
487
  //
 
488
  // Install EndOfPeiPpi
 
489
  //
 
490
  Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);
 
491
  ASSERT_EFI_ERROR (Status);
 
492
 
 
493
  //
 
494
  // report status code on S3 resume
 
495
  //
 
496
  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE);
 
497
 
 
498
  PERF_CODE (
 
499
    WriteToOsS3PerformanceData ();
 
500
    );
 
501
 
 
502
  AsmTransferControl = (ASM_TRANSFER_CONTROL)(UINTN)PeiS3ResumeState->AsmTransferControl;
 
503
  if (Facs->XFirmwareWakingVector != 0) {
 
504
    //
 
505
    // Switch to native waking vector
 
506
    //
 
507
    TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
 
508
    if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
 
509
        ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
 
510
        ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
 
511
      //
 
512
      // X64 long mode waking vector
 
513
      //
 
514
      DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
 
515
      if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
516
        AsmEnablePaging64 (
 
517
          0x38,
 
518
          Facs->XFirmwareWakingVector,
 
519
          0,
 
520
          0,
 
521
          (UINT64)(UINTN)TempStackTop
 
522
          );
 
523
      } else {
 
524
        //
 
525
        // Report Status code that no valid waking vector is found
 
526
        //
 
527
        REPORT_STATUS_CODE (
 
528
          EFI_ERROR_CODE | EFI_ERROR_MAJOR,
 
529
          (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
 
530
          );
 
531
        DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
 
532
        ASSERT (FALSE);
 
533
        CpuDeadLoop ();
 
534
        return ;
 
535
      }
 
536
    } else {
 
537
      //
 
538
      // IA32 protected mode waking vector (Page disabled)
 
539
      //
 
540
      DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
 
541
      SwitchStack (
 
542
        (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector,
 
543
        NULL,
 
544
        NULL,
 
545
        (VOID *)(UINTN)TempStackTop
 
546
        );
 
547
    }
 
548
  } else {
 
549
    //
 
550
    // 16bit Realmode waking vector
 
551
    //
 
552
    DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
 
553
    AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
 
554
  }
 
555
 
 
556
  //
 
557
  // Report Status code the failure of S3Resume
 
558
  //
 
559
  REPORT_STATUS_CODE (
 
560
    EFI_ERROR_CODE | EFI_ERROR_MAJOR,
 
561
    (EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_EC_S3_OS_WAKE_ERROR)
 
562
    );
 
563
 
 
564
  //
 
565
  // Never run to here
 
566
  //
 
567
  CpuDeadLoop();
 
568
}
 
569
 
 
570
/**
 
571
  Restore S3 page table because we do not trust ACPINvs content.
 
572
  If BootScriptExector driver will not run in 64-bit mode, this function will do nothing. 
 
573
 
 
574
  @param S3NvsPageTableAddress   PageTableAddress in ACPINvs
 
575
  @param Build4GPageTableOnly    If BIOS just build 4G page table only
 
576
**/
 
577
VOID
 
578
RestoreS3PageTables (
 
579
  IN UINTN                                         S3NvsPageTableAddress,
 
580
  IN BOOLEAN                                       Build4GPageTableOnly
 
581
  )
 
582
{
 
583
  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
584
    UINT32                                        RegEax;
 
585
    UINT32                                        RegEdx;
 
586
    UINT8                                         PhysicalAddressBits;
 
587
    EFI_PHYSICAL_ADDRESS                          PageAddress;
 
588
    UINTN                                         IndexOfPml4Entries;
 
589
    UINTN                                         IndexOfPdpEntries;
 
590
    UINTN                                         IndexOfPageDirectoryEntries;
 
591
    UINT32                                        NumberOfPml4EntriesNeeded;
 
592
    UINT32                                        NumberOfPdpEntriesNeeded;
 
593
    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMapLevel4Entry;
 
594
    PAGE_MAP_AND_DIRECTORY_POINTER                *PageMap;
 
595
    PAGE_MAP_AND_DIRECTORY_POINTER                *PageDirectoryPointerEntry;
 
596
    PAGE_TABLE_ENTRY                              *PageDirectoryEntry;
 
597
    VOID                                          *Hob;
 
598
    BOOLEAN                                       Page1GSupport;
 
599
    PAGE_TABLE_1G_ENTRY                           *PageDirectory1GEntry;
 
600
 
 
601
    //
 
602
    // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information.
 
603
    // The whole page table is too large to be saved in SMRAM.
 
604
    //
 
605
    // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page.
 
606
    //
 
607
    DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));
 
608
 
 
609
    //
 
610
    // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.
 
611
    //
 
612
    PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
 
613
    S3NvsPageTableAddress += SIZE_4KB;
 
614
    
 
615
    Page1GSupport = FALSE;
 
616
    if (PcdGetBool(PcdUse1GPageTable)) {
 
617
      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 
618
      if (RegEax >= 0x80000001) {
 
619
        AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
 
620
        if ((RegEdx & BIT26) != 0) {
 
621
          Page1GSupport = TRUE;
 
622
        }
 
623
      }
 
624
    }
 
625
    
 
626
    //
 
627
    // Get physical address bits supported.
 
628
    //
 
629
    Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
 
630
    if (Hob != NULL) {
 
631
      PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
 
632
    } else {
 
633
      AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 
634
      if (RegEax >= 0x80000008) {
 
635
        AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 
636
        PhysicalAddressBits = (UINT8) RegEax;
 
637
      } else {
 
638
        PhysicalAddressBits = 36;
 
639
      }
 
640
    }
 
641
    
 
642
    //
 
643
    // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
 
644
    //
 
645
    ASSERT (PhysicalAddressBits <= 52);
 
646
    if (PhysicalAddressBits > 48) {
 
647
      PhysicalAddressBits = 48;
 
648
    }
 
649
 
 
650
    //
 
651
    // NOTE: In order to save time to create full page table, we just create 4G page table by default.
 
652
    // And let PF handler in BootScript driver to create more on request.
 
653
    //
 
654
    if (Build4GPageTableOnly) {
 
655
      PhysicalAddressBits = 32;
 
656
      ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));
 
657
    }
 
658
    //
 
659
    // Calculate the table entries needed.
 
660
    //
 
661
    if (PhysicalAddressBits <= 39) {
 
662
      NumberOfPml4EntriesNeeded = 1;
 
663
      NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
 
664
    } else {
 
665
      NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
 
666
      NumberOfPdpEntriesNeeded = 512;
 
667
    }
 
668
    
 
669
    PageMapLevel4Entry = PageMap;
 
670
    PageAddress        = 0;
 
671
    for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
 
672
      //
 
673
      // Each PML4 entry points to a page of Page Directory Pointer entires.
 
674
      // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
 
675
      //
 
676
      PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
 
677
      S3NvsPageTableAddress += SIZE_4KB;
 
678
    
 
679
      //
 
680
      // Make a PML4 Entry
 
681
      //
 
682
      PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;
 
683
      PageMapLevel4Entry->Bits.ReadWrite = 1;
 
684
      PageMapLevel4Entry->Bits.Present = 1;
 
685
 
 
686
      if (Page1GSupport) {
 
687
        PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
 
688
    
 
689
        for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
 
690
          //
 
691
          // Fill in the Page Directory entries
 
692
          //
 
693
          PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
 
694
          PageDirectory1GEntry->Bits.ReadWrite = 1;
 
695
          PageDirectory1GEntry->Bits.Present = 1;
 
696
          PageDirectory1GEntry->Bits.MustBe1 = 1;
 
697
        }
 
698
      } else {
 
699
        for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
 
700
          //
 
701
          // Each Directory Pointer entries points to a page of Page Directory entires.
 
702
          // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
 
703
          //       
 
704
          PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress;
 
705
          S3NvsPageTableAddress += SIZE_4KB;
 
706
    
 
707
          //
 
708
          // Fill in a Page Directory Pointer Entries
 
709
          //
 
710
          PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;
 
711
          PageDirectoryPointerEntry->Bits.ReadWrite = 1;
 
712
          PageDirectoryPointerEntry->Bits.Present = 1;
 
713
    
 
714
          for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
 
715
            //
 
716
            // Fill in the Page Directory entries
 
717
            //
 
718
            PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
 
719
            PageDirectoryEntry->Bits.ReadWrite = 1;
 
720
            PageDirectoryEntry->Bits.Present = 1;
 
721
            PageDirectoryEntry->Bits.MustBe1 = 1;
 
722
          }
 
723
        }
 
724
      }
 
725
    }
 
726
    return ;
 
727
  } else {
 
728
        //
 
729
        // If DXE is running 32-bit mode, no need to establish page table.
 
730
        //
 
731
    return ;
 
732
  }
 
733
}
 
734
 
 
735
/**
 
736
  Jump to boot script executor driver.
 
737
 
 
738
  The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table.
 
739
 
 
740
  @param  AcpiS3Context                 a pointer to a structure of ACPI_S3_CONTEXT
 
741
  @param  EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in
 
742
                                        boot script execute driver
 
743
**/
 
744
VOID
 
745
EFIAPI
 
746
S3ResumeExecuteBootScript (
 
747
  IN ACPI_S3_CONTEXT                *AcpiS3Context,
 
748
  IN BOOT_SCRIPT_EXECUTOR_VARIABLE  *EfiBootScriptExecutorVariable
 
749
  )
 
750
{
 
751
  EFI_STATUS                 Status;
 
752
  PEI_SMM_ACCESS_PPI         *SmmAccess;
 
753
  UINTN                      Index;
 
754
  VOID                       *GuidHob;
 
755
  IA32_DESCRIPTOR            *IdtDescriptor;
 
756
  VOID                       *IdtBuffer;
 
757
  PEI_S3_RESUME_STATE        *PeiS3ResumeState;
 
758
  BOOLEAN                    InterruptStatus;
 
759
 
 
760
  DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n"));
 
761
 
 
762
  //
 
763
  // Attempt to use content from SMRAM first
 
764
  //
 
765
  GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
 
766
  if (GuidHob != NULL) {
 
767
    //
 
768
    // Last step for SMM - send SMI for initialization
 
769
    //
 
770
 
 
771
    //
 
772
    // Send SMI to APs
 
773
    //    
 
774
    SendSmiIpiAllExcludingSelf ();
 
775
    //
 
776
    // Send SMI to BSP
 
777
    //
 
778
    SendSmiIpi (GetApicId ());
 
779
 
 
780
    Status = PeiServicesLocatePpi (
 
781
                              &gPeiSmmAccessPpiGuid,
 
782
                              0,
 
783
                              NULL,
 
784
                              (VOID **) &SmmAccess
 
785
                              );
 
786
    if (!EFI_ERROR (Status)) {
 
787
      DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n"));
 
788
  
 
789
      for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
 
790
        Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
 
791
      }
 
792
 
 
793
      DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n"));
 
794
  
 
795
      for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
 
796
        Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
 
797
      }
 
798
    }
 
799
  }
 
800
 
 
801
  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
802
    AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);
 
803
  }
 
804
 
 
805
  if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
 
806
    //
 
807
    // On some platform, such as ECP, a dispatch node in boot script table may execute a 32-bit PEIM which may need PeiServices
 
808
    // pointer. So PeiServices need preserve in (IDTBase- sizeof (UINTN)). 
 
809
    //
 
810
    IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
 
811
    //
 
812
    // Make sure the newly allcated IDT align with 16-bytes
 
813
    // 
 
814
    IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16));
 
815
    ASSERT (IdtBuffer != NULL);
 
816
    //
 
817
    // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer
 
818
    // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code
 
819
    // 
 
820
    ZeroMem (IdtBuffer, 16);
 
821
    AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer);
 
822
    CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1));
 
823
    IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16);
 
824
    *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();
 
825
  }
 
826
 
 
827
  InterruptStatus = SaveAndDisableInterrupts ();
 
828
  //
 
829
  // Need to make sure the GDT is loaded with values that support long mode and real mode.
 
830
  //
 
831
  AsmWriteGdtr (&mGdt);
 
832
  //
 
833
  // update segment selectors per the new GDT.
 
834
  //
 
835
  AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
 
836
  //
 
837
  // Restore interrupt state.
 
838
  //
 
839
  SetInterruptState (InterruptStatus);
 
840
 
 
841
  //
 
842
  // Prepare data for return back
 
843
  //
 
844
  PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState));
 
845
  ASSERT (PeiS3ResumeState != NULL);
 
846
  DEBUG (( EFI_D_ERROR, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));
 
847
  PeiS3ResumeState->ReturnCs           = 0x10;
 
848
  PeiS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;
 
849
  PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;
 
850
  //
 
851
  // Save IDT
 
852
  //
 
853
  AsmReadIdtr (&PeiS3ResumeState->Idtr);
 
854
  
 
855
  //
 
856
  // Report Status Code to indicate S3 boot script execution
 
857
  //
 
858
  REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_S3_BOOT_SCRIPT);
 
859
 
 
860
  PERF_START (NULL, "ScriptExec", NULL, 0);
 
861
 
 
862
  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
863
    //
 
864
    // X64 S3 Resume
 
865
    //
 
866
    DEBUG (( EFI_D_ERROR, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n"));
 
867
 
 
868
    //
 
869
    // Switch to long mode to complete resume.
 
870
    //
 
871
    AsmEnablePaging64 (
 
872
      0x38,
 
873
      EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
 
874
      (UINT64)(UINTN)AcpiS3Context,
 
875
      (UINT64)(UINTN)PeiS3ResumeState,
 
876
      (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
 
877
      );
 
878
  } else {
 
879
    //
 
880
    // IA32 S3 Resume
 
881
    //
 
882
    DEBUG (( EFI_D_ERROR, "transfer control to Standalone Boot Script Executor\r\n"));
 
883
    SwitchStack (
 
884
      (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
 
885
      (VOID *)AcpiS3Context,
 
886
      (VOID *)PeiS3ResumeState,
 
887
      (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
 
888
      );
 
889
  }
 
890
 
 
891
  //
 
892
  // Never run to here
 
893
  //
 
894
  CpuDeadLoop();
 
895
}
 
896
/**
 
897
  Restores the platform to its preboot configuration for an S3 resume and
 
898
  jumps to the OS waking vector.
 
899
 
 
900
  This function will restore the platform to its pre-boot configuration that was
 
901
  pre-stored in the boot script table and transfer control to OS waking vector.
 
902
  Upon invocation, this function is responsible for locating the following
 
903
  information before jumping to OS waking vector:
 
904
    - ACPI tables
 
905
    - boot script table
 
906
    - any other information that it needs
 
907
 
 
908
  The S3RestoreConfig() function then executes the pre-stored boot script table
 
909
  and transitions the platform to the pre-boot state. The boot script is recorded
 
910
  during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
 
911
  EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions.  Finally, this function
 
912
  transfers control to the OS waking vector. If the OS supports only a real-mode
 
913
  waking vector, this function will switch from flat mode to real mode before
 
914
  jumping to the waking vector.  If all platform pre-boot configurations are
 
915
  successfully restored and all other necessary information is ready, this
 
916
  function will never return and instead will directly jump to the OS waking
 
917
  vector. If this function returns, it indicates that the attempt to resume
 
918
  from the ACPI S3 sleep state failed.
 
919
 
 
920
  @param[in] This         Pointer to this instance of the PEI_S3_RESUME_PPI
 
921
 
 
922
  @retval EFI_ABORTED     Execution of the S3 resume boot script table failed.
 
923
  @retval EFI_NOT_FOUND   Some necessary information that is used for the S3
 
924
                          resume boot path could not be located.
 
925
 
 
926
**/
 
927
EFI_STATUS
 
928
EFIAPI
 
929
S3RestoreConfig2 (
 
930
  IN EFI_PEI_S3_RESUME2_PPI  *This
 
931
  )
 
932
{
 
933
  EFI_STATUS                                    Status;
 
934
  PEI_SMM_ACCESS_PPI                            *SmmAccess;
 
935
  UINTN                                         Index;
 
936
  ACPI_S3_CONTEXT                               *AcpiS3Context;
 
937
  EFI_PHYSICAL_ADDRESS                          TempEfiBootScriptExecutorVariable;
 
938
  EFI_PHYSICAL_ADDRESS                          TempAcpiS3Context;
 
939
  BOOT_SCRIPT_EXECUTOR_VARIABLE                 *EfiBootScriptExecutorVariable;
 
940
  UINTN                                         VarSize;
 
941
  EFI_SMRAM_DESCRIPTOR                          *SmramDescriptor;
 
942
  SMM_S3_RESUME_STATE                           *SmmS3ResumeState;
 
943
  VOID                                          *GuidHob;
 
944
  BOOLEAN                                       Build4GPageTableOnly;
 
945
  BOOLEAN                                       InterruptStatus;
 
946
 
 
947
  TempAcpiS3Context = 0;
 
948
  TempEfiBootScriptExecutorVariable = 0;
 
949
 
 
950
  DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));
 
951
 
 
952
  VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
 
953
  Status = RestoreLockBox (
 
954
             &gEfiAcpiVariableGuid,
 
955
             &TempAcpiS3Context,
 
956
             &VarSize
 
957
             );
 
958
  ASSERT_EFI_ERROR (Status);
 
959
 
 
960
  Status = RestoreLockBox (
 
961
             &gEfiAcpiS3ContextGuid,
 
962
             NULL,
 
963
             NULL
 
964
             );
 
965
  ASSERT_EFI_ERROR (Status);
 
966
 
 
967
  AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
 
968
  ASSERT (AcpiS3Context != NULL);
 
969
 
 
970
  VarSize   = sizeof (EFI_PHYSICAL_ADDRESS);
 
971
  Status = RestoreLockBox (
 
972
             &gEfiBootScriptExecutorVariableGuid,
 
973
             &TempEfiBootScriptExecutorVariable,
 
974
             &VarSize
 
975
             );
 
976
  ASSERT_EFI_ERROR (Status);
 
977
 
 
978
  Status = RestoreLockBox (
 
979
             &gEfiBootScriptExecutorContextGuid,
 
980
             NULL,
 
981
             NULL
 
982
             );
 
983
  ASSERT_EFI_ERROR (Status);
 
984
 
 
985
  EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable;
 
986
  ASSERT (EfiBootScriptExecutorVariable != NULL);
 
987
 
 
988
  DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context));
 
989
  DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));
 
990
  DEBUG (( EFI_D_ERROR, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));
 
991
  DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));
 
992
  DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));
 
993
  DEBUG (( EFI_D_ERROR, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));
 
994
 
 
995
  //
 
996
  // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor.
 
997
  // Script dispatch image and context (parameter) are handled by platform.
 
998
  // We just use restore all lock box in place, no need restore one by one.
 
999
  //
 
1000
  Status = RestoreAllLockBoxInPlace ();
 
1001
  ASSERT_EFI_ERROR (Status);
 
1002
  if (EFI_ERROR (Status)) {
 
1003
    // Something wrong
 
1004
    CpuDeadLoop ();
 
1005
  }
 
1006
 
 
1007
  if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
 
1008
    //
 
1009
    // Need reconstruct page table here, since we do not trust ACPINvs.
 
1010
    //
 
1011
    if (IsLongModeWakingVector (AcpiS3Context)) {
 
1012
      Build4GPageTableOnly = FALSE;
 
1013
    } else {
 
1014
      Build4GPageTableOnly = TRUE;
 
1015
    }
 
1016
    RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);
 
1017
  }
 
1018
 
 
1019
  //
 
1020
  // Attempt to use content from SMRAM first
 
1021
  //
 
1022
  GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
 
1023
  if (GuidHob != NULL) {
 
1024
    Status = PeiServicesLocatePpi (
 
1025
                              &gPeiSmmAccessPpiGuid,
 
1026
                              0,
 
1027
                              NULL,
 
1028
                              (VOID **) &SmmAccess
 
1029
                              );
 
1030
    for (Index = 0; !EFI_ERROR (Status); Index++) {
 
1031
      Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
 
1032
    }
 
1033
 
 
1034
    SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
 
1035
    SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
 
1036
 
 
1037
    SmmS3ResumeState->ReturnCs           = AsmReadCs ();
 
1038
    SmmS3ResumeState->ReturnEntryPoint   = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;
 
1039
    SmmS3ResumeState->ReturnContext1     = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
 
1040
    SmmS3ResumeState->ReturnContext2     = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;
 
1041
    SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;
 
1042
 
 
1043
    DEBUG (( EFI_D_ERROR, "SMM S3 Signature                = %x\n", SmmS3ResumeState->Signature));
 
1044
    DEBUG (( EFI_D_ERROR, "SMM S3 Stack Base               = %x\n", SmmS3ResumeState->SmmS3StackBase));
 
1045
    DEBUG (( EFI_D_ERROR, "SMM S3 Stack Size               = %x\n", SmmS3ResumeState->SmmS3StackSize));
 
1046
    DEBUG (( EFI_D_ERROR, "SMM S3 Resume Entry Point       = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint));
 
1047
    DEBUG (( EFI_D_ERROR, "SMM S3 CR0                      = %x\n", SmmS3ResumeState->SmmS3Cr0));
 
1048
    DEBUG (( EFI_D_ERROR, "SMM S3 CR3                      = %x\n", SmmS3ResumeState->SmmS3Cr3));
 
1049
    DEBUG (( EFI_D_ERROR, "SMM S3 CR4                      = %x\n", SmmS3ResumeState->SmmS3Cr4));
 
1050
    DEBUG (( EFI_D_ERROR, "SMM S3 Return CS                = %x\n", SmmS3ResumeState->ReturnCs));
 
1051
    DEBUG (( EFI_D_ERROR, "SMM S3 Return Entry Point       = %x\n", SmmS3ResumeState->ReturnEntryPoint));
 
1052
    DEBUG (( EFI_D_ERROR, "SMM S3 Return Context1          = %x\n", SmmS3ResumeState->ReturnContext1));
 
1053
    DEBUG (( EFI_D_ERROR, "SMM S3 Return Context2          = %x\n", SmmS3ResumeState->ReturnContext2));
 
1054
    DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer     = %x\n", SmmS3ResumeState->ReturnStackPointer));
 
1055
    DEBUG (( EFI_D_ERROR, "SMM S3 Smst                     = %x\n", SmmS3ResumeState->Smst));
 
1056
 
 
1057
    if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
 
1058
      SwitchStack (
 
1059
        (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,
 
1060
        (VOID *)AcpiS3Context,
 
1061
        0,
 
1062
        (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize)
 
1063
        );
 
1064
    }
 
1065
    if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
 
1066
      //
 
1067
      // Switch to long mode to complete resume.
 
1068
      //
 
1069
 
 
1070
      InterruptStatus = SaveAndDisableInterrupts ();
 
1071
      //
 
1072
      // Need to make sure the GDT is loaded with values that support long mode and real mode.
 
1073
      //
 
1074
      AsmWriteGdtr (&mGdt);
 
1075
      //
 
1076
      // update segment selectors per the new GDT.
 
1077
      //      
 
1078
      AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
 
1079
      //
 
1080
      // Restore interrupt state.
 
1081
      //
 
1082
      SetInterruptState (InterruptStatus);
 
1083
 
 
1084
      AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);
 
1085
 
 
1086
      //
 
1087
      // Disable interrupt of Debug timer, since IDT table cannot work in long mode.
 
1088
      // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,
 
1089
      // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.
 
1090
      //
 
1091
      SaveAndSetDebugTimerInterrupt (FALSE);
 
1092
 
 
1093
      AsmEnablePaging64 (
 
1094
        0x38,
 
1095
        SmmS3ResumeState->SmmS3ResumeEntryPoint,
 
1096
        (UINT64)(UINTN)AcpiS3Context,
 
1097
        0,
 
1098
        SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize
 
1099
        );
 
1100
    }
 
1101
 
 
1102
  }
 
1103
 
 
1104
  S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable );
 
1105
  return EFI_SUCCESS;
 
1106
}
 
1107
/**
 
1108
  Main entry for S3 Resume PEIM.
 
1109
 
 
1110
  This routine is to install EFI_PEI_S3_RESUME2_PPI.
 
1111
  
 
1112
  @param  FileHandle              Handle of the file being invoked.
 
1113
  @param  PeiServices             Pointer to PEI Services table.
 
1114
 
 
1115
  @retval EFI_SUCCESS S3Resume Ppi is installed successfully.
 
1116
 
 
1117
**/
 
1118
EFI_STATUS
 
1119
EFIAPI
 
1120
PeimS3ResumeEntryPoint (
 
1121
  IN EFI_PEI_FILE_HANDLE       FileHandle,
 
1122
  IN CONST EFI_PEI_SERVICES    **PeiServices
 
1123
  )
 
1124
{
 
1125
  EFI_STATUS  Status;
 
1126
 
 
1127
  //
 
1128
  // Install S3 Resume Ppi
 
1129
  //
 
1130
  Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
 
1131
  ASSERT_EFI_ERROR (Status);
 
1132
 
 
1133
  return EFI_SUCCESS;
 
1134
}
 
1135