]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c
Only disable Debug Timer for x64 platforms in S3RestoreConfig2().
[mirror_edk2.git] / UefiCpuPkg / Universal / Acpi / S3Resume2Pei / S3Resume.c
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 //
445 // NOTE: Because Debug Timer interrupt and system interrupts will be disabled
446 // in BootScriptExecuteDxe, the rest code in S3ResumeBootOs() cannot be halted
447 // by soft debugger.
448 //
449
450 PERF_END (NULL, "ScriptExec", NULL, 0);
451
452 //
453 // Install BootScriptDonePpi
454 //
455 Status = PeiServicesInstallPpi (&mPpiListPostScriptTable);
456 ASSERT_EFI_ERROR (Status);
457
458 //
459 // Get ACPI Table Address
460 //
461 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable));
462
463 if ((Facs == NULL) ||
464 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
465 ((Facs->FirmwareWakingVector == 0) && (Facs->XFirmwareWakingVector == 0)) ) {
466 CpuDeadLoop ();
467 return ;
468 }
469
470 //
471 // Install EndOfPeiPpi
472 //
473 Status = PeiServicesInstallPpi (&mPpiListEndOfPeiTable);
474 ASSERT_EFI_ERROR (Status);
475
476 //
477 // report status code on S3 resume
478 //
479 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_PC_OS_WAKE);
480
481 PERF_CODE (
482 WriteToOsS3PerformanceData ();
483 );
484
485 AsmTransferControl = (ASM_TRANSFER_CONTROL)(UINTN)PeiS3ResumeState->AsmTransferControl;
486 if (Facs->XFirmwareWakingVector != 0) {
487 //
488 // Switch to native waking vector
489 //
490 TempStackTop = (UINTN)&TempStack + sizeof(TempStack);
491 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
492 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0) &&
493 ((Facs->Flags & EFI_ACPI_4_0_OSPM_64BIT_WAKE__F) != 0)) {
494 //
495 // X64 long mode waking vector
496 //
497 DEBUG (( EFI_D_ERROR, "Transfer to 64bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
498 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
499 AsmEnablePaging64 (
500 0x38,
501 Facs->XFirmwareWakingVector,
502 0,
503 0,
504 (UINT64)(UINTN)TempStackTop
505 );
506 } else {
507 DEBUG (( EFI_D_ERROR, "Unsupported for 32bit DXE transfer to 64bit OS waking vector!\r\n"));
508 ASSERT (FALSE);
509 }
510 } else {
511 //
512 // IA32 protected mode waking vector (Page disabled)
513 //
514 DEBUG (( EFI_D_ERROR, "Transfer to 32bit OS waking vector - %x\r\n", (UINTN)Facs->XFirmwareWakingVector));
515 SwitchStack (
516 (SWITCH_STACK_ENTRY_POINT) (UINTN) Facs->XFirmwareWakingVector,
517 NULL,
518 NULL,
519 (VOID *)(UINTN)TempStackTop
520 );
521 }
522 } else {
523 //
524 // 16bit Realmode waking vector
525 //
526 DEBUG (( EFI_D_ERROR, "Transfer to 16bit OS waking vector - %x\r\n", (UINTN)Facs->FirmwareWakingVector));
527 AsmTransferControl (Facs->FirmwareWakingVector, 0x0);
528 }
529
530 //
531 // Never run to here
532 //
533 CpuDeadLoop();
534 }
535
536 /**
537 Restore S3 page table because we do not trust ACPINvs content.
538 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
539
540 @param S3NvsPageTableAddress PageTableAddress in ACPINvs
541 @param Build4GPageTableOnly If BIOS just build 4G page table only
542 **/
543 VOID
544 RestoreS3PageTables (
545 IN UINTN S3NvsPageTableAddress,
546 IN BOOLEAN Build4GPageTableOnly
547 )
548 {
549 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
550 UINT32 RegEax;
551 UINT32 RegEdx;
552 UINT8 PhysicalAddressBits;
553 EFI_PHYSICAL_ADDRESS PageAddress;
554 UINTN IndexOfPml4Entries;
555 UINTN IndexOfPdpEntries;
556 UINTN IndexOfPageDirectoryEntries;
557 UINT32 NumberOfPml4EntriesNeeded;
558 UINT32 NumberOfPdpEntriesNeeded;
559 PAGE_MAP_AND_DIRECTORY_POINTER *PageMapLevel4Entry;
560 PAGE_MAP_AND_DIRECTORY_POINTER *PageMap;
561 PAGE_MAP_AND_DIRECTORY_POINTER *PageDirectoryPointerEntry;
562 PAGE_TABLE_ENTRY *PageDirectoryEntry;
563 VOID *Hob;
564 BOOLEAN Page1GSupport;
565 PAGE_TABLE_1G_ENTRY *PageDirectory1GEntry;
566
567 //
568 // NOTE: We have to ASSUME the page table generation format, because we do not know whole page table information.
569 // The whole page table is too large to be saved in SMRAM.
570 //
571 // The assumption is : whole page table is allocated in CONTINOUS memory and CR3 points to TOP page.
572 //
573 DEBUG ((EFI_D_ERROR, "S3NvsPageTableAddress - %x (%x)\n", (UINTN)S3NvsPageTableAddress, (UINTN)Build4GPageTableOnly));
574
575 //
576 // By architecture only one PageMapLevel4 exists - so lets allocate storgage for it.
577 //
578 PageMap = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
579 S3NvsPageTableAddress += SIZE_4KB;
580
581 Page1GSupport = FALSE;
582 if (PcdGetBool(PcdUse1GPageTable)) {
583 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
584 if (RegEax >= 0x80000001) {
585 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
586 if ((RegEdx & BIT26) != 0) {
587 Page1GSupport = TRUE;
588 }
589 }
590 }
591
592 //
593 // Get physical address bits supported.
594 //
595 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
596 if (Hob != NULL) {
597 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
598 } else {
599 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
600 if (RegEax >= 0x80000008) {
601 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
602 PhysicalAddressBits = (UINT8) RegEax;
603 } else {
604 PhysicalAddressBits = 36;
605 }
606 }
607
608 //
609 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
610 //
611 ASSERT (PhysicalAddressBits <= 52);
612 if (PhysicalAddressBits > 48) {
613 PhysicalAddressBits = 48;
614 }
615
616 //
617 // NOTE: In order to save time to create full page table, we just create 4G page table by default.
618 // And let PF handler in BootScript driver to create more on request.
619 //
620 if (Build4GPageTableOnly) {
621 PhysicalAddressBits = 32;
622 ZeroMem (PageMap, EFI_PAGES_TO_SIZE(2));
623 }
624 //
625 // Calculate the table entries needed.
626 //
627 if (PhysicalAddressBits <= 39) {
628 NumberOfPml4EntriesNeeded = 1;
629 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
630 } else {
631 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
632 NumberOfPdpEntriesNeeded = 512;
633 }
634
635 PageMapLevel4Entry = PageMap;
636 PageAddress = 0;
637 for (IndexOfPml4Entries = 0; IndexOfPml4Entries < NumberOfPml4EntriesNeeded; IndexOfPml4Entries++, PageMapLevel4Entry++) {
638 //
639 // Each PML4 entry points to a page of Page Directory Pointer entires.
640 // So lets allocate space for them and fill them in in the IndexOfPdpEntries loop.
641 //
642 PageDirectoryPointerEntry = (PAGE_MAP_AND_DIRECTORY_POINTER *)S3NvsPageTableAddress;
643 S3NvsPageTableAddress += SIZE_4KB;
644
645 //
646 // Make a PML4 Entry
647 //
648 PageMapLevel4Entry->Uint64 = (UINT64)(UINTN)PageDirectoryPointerEntry;
649 PageMapLevel4Entry->Bits.ReadWrite = 1;
650 PageMapLevel4Entry->Bits.Present = 1;
651
652 if (Page1GSupport) {
653 PageDirectory1GEntry = (VOID *) PageDirectoryPointerEntry;
654
655 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectory1GEntry++, PageAddress += SIZE_1GB) {
656 //
657 // Fill in the Page Directory entries
658 //
659 PageDirectory1GEntry->Uint64 = (UINT64)PageAddress;
660 PageDirectory1GEntry->Bits.ReadWrite = 1;
661 PageDirectory1GEntry->Bits.Present = 1;
662 PageDirectory1GEntry->Bits.MustBe1 = 1;
663 }
664 } else {
665 for (IndexOfPdpEntries = 0; IndexOfPdpEntries < NumberOfPdpEntriesNeeded; IndexOfPdpEntries++, PageDirectoryPointerEntry++) {
666 //
667 // Each Directory Pointer entries points to a page of Page Directory entires.
668 // So allocate space for them and fill them in in the IndexOfPageDirectoryEntries loop.
669 //
670 PageDirectoryEntry = (PAGE_TABLE_ENTRY *)S3NvsPageTableAddress;
671 S3NvsPageTableAddress += SIZE_4KB;
672
673 //
674 // Fill in a Page Directory Pointer Entries
675 //
676 PageDirectoryPointerEntry->Uint64 = (UINT64)(UINTN)PageDirectoryEntry;
677 PageDirectoryPointerEntry->Bits.ReadWrite = 1;
678 PageDirectoryPointerEntry->Bits.Present = 1;
679
680 for (IndexOfPageDirectoryEntries = 0; IndexOfPageDirectoryEntries < 512; IndexOfPageDirectoryEntries++, PageDirectoryEntry++, PageAddress += SIZE_2MB) {
681 //
682 // Fill in the Page Directory entries
683 //
684 PageDirectoryEntry->Uint64 = (UINT64)PageAddress;
685 PageDirectoryEntry->Bits.ReadWrite = 1;
686 PageDirectoryEntry->Bits.Present = 1;
687 PageDirectoryEntry->Bits.MustBe1 = 1;
688 }
689 }
690 }
691 }
692 return ;
693 } else {
694 //
695 // If DXE is running 32-bit mode, no need to establish page table.
696 //
697 return ;
698 }
699 }
700
701 /**
702 Jump to boot script executor driver.
703
704 The function will close and lock SMRAM and then jump to boot script execute driver to executing S3 boot script table.
705
706 @param AcpiS3Context a pointer to a structure of ACPI_S3_CONTEXT
707 @param EfiBootScriptExecutorVariable The function entry to executing S3 boot Script table. This function is build in
708 boot script execute driver
709 **/
710 VOID
711 EFIAPI
712 S3ResumeExecuteBootScript (
713 IN ACPI_S3_CONTEXT *AcpiS3Context,
714 IN BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable
715 )
716 {
717 EFI_STATUS Status;
718 PEI_SMM_ACCESS_PPI *SmmAccess;
719 UINTN Index;
720 VOID *GuidHob;
721 IA32_DESCRIPTOR *IdtDescriptor;
722 VOID *IdtBuffer;
723 PEI_S3_RESUME_STATE *PeiS3ResumeState;
724 BOOLEAN InterruptStatus;
725
726 DEBUG ((EFI_D_ERROR, "S3ResumeExecuteBootScript()\n"));
727
728 //
729 // Attempt to use content from SMRAM first
730 //
731 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
732 if (GuidHob != NULL) {
733 //
734 // Last step for SMM - send SMI for initialization
735 //
736
737 //
738 // Send SMI to APs
739 //
740 SendSmiIpiAllExcludingSelf ();
741 //
742 // Send SMI to BSP
743 //
744 SendSmiIpi (GetApicId ());
745
746 Status = PeiServicesLocatePpi (
747 &gPeiSmmAccessPpiGuid,
748 0,
749 NULL,
750 (VOID **) &SmmAccess
751 );
752 if (!EFI_ERROR (Status)) {
753 DEBUG ((EFI_D_ERROR, "Close all SMRAM regions before executing boot script\n"));
754
755 for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
756 Status = SmmAccess->Close ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
757 }
758
759 DEBUG ((EFI_D_ERROR, "Lock all SMRAM regions before executing boot script\n"));
760
761 for (Index = 0, Status = EFI_SUCCESS; !EFI_ERROR (Status); Index++) {
762 Status = SmmAccess->Lock ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
763 }
764 }
765 }
766
767 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
768 AsmWriteCr3 ((UINTN)AcpiS3Context->S3NvsPageTableAddress);
769 }
770
771 if (FeaturePcdGet (PcdFrameworkCompatibilitySupport)) {
772 //
773 // On some platform, such as ECP, a dispatch node in boot script table may execute a 32-bit PEIM which may need PeiServices
774 // pointer. So PeiServices need preserve in (IDTBase- sizeof (UINTN)).
775 //
776 IdtDescriptor = (IA32_DESCRIPTOR *) (UINTN) (AcpiS3Context->IdtrProfile);
777 //
778 // Make sure the newly allcated IDT align with 16-bytes
779 //
780 IdtBuffer = AllocatePages (EFI_SIZE_TO_PAGES((IdtDescriptor->Limit + 1) + 16));
781 ASSERT (IdtBuffer != NULL);
782 //
783 // Additional 16 bytes allocated to save IA32 IDT descriptor and Pei Service Table Pointer
784 // IA32 IDT descriptor will be used to setup IA32 IDT table for 32-bit Framework Boot Script code
785 //
786 ZeroMem (IdtBuffer, 16);
787 AsmReadIdtr ((IA32_DESCRIPTOR *)IdtBuffer);
788 CopyMem ((VOID*)((UINT8*)IdtBuffer + 16),(VOID*)(IdtDescriptor->Base), (IdtDescriptor->Limit + 1));
789 IdtDescriptor->Base = (UINTN)((UINT8*)IdtBuffer + 16);
790 *(UINTN*)(IdtDescriptor->Base - sizeof(UINTN)) = (UINTN)GetPeiServicesTablePointer ();
791 }
792
793 InterruptStatus = SaveAndDisableInterrupts ();
794 //
795 // Need to make sure the GDT is loaded with values that support long mode and real mode.
796 //
797 AsmWriteGdtr (&mGdt);
798 //
799 // update segment selectors per the new GDT.
800 //
801 AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
802 //
803 // Restore interrupt state.
804 //
805 SetInterruptState (InterruptStatus);
806
807 //
808 // Prepare data for return back
809 //
810 PeiS3ResumeState = AllocatePool (sizeof(*PeiS3ResumeState));
811 ASSERT (PeiS3ResumeState != NULL);
812 DEBUG (( EFI_D_ERROR, "PeiS3ResumeState - %x\r\n", PeiS3ResumeState));
813 PeiS3ResumeState->ReturnCs = 0x10;
814 PeiS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeBootOs;
815 PeiS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;
816 //
817 // Save IDT
818 //
819 AsmReadIdtr (&PeiS3ResumeState->Idtr);
820
821 PERF_START (NULL, "ScriptExec", NULL, 0);
822
823 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
824 //
825 // X64 S3 Resume
826 //
827 DEBUG (( EFI_D_ERROR, "Enable X64 and transfer control to Standalone Boot Script Executor\r\n"));
828
829 //
830 // Switch to long mode to complete resume.
831 //
832 AsmEnablePaging64 (
833 0x38,
834 EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
835 (UINT64)(UINTN)AcpiS3Context,
836 (UINT64)(UINTN)PeiS3ResumeState,
837 (UINT64)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
838 );
839 } else {
840 //
841 // IA32 S3 Resume
842 //
843 DEBUG (( EFI_D_ERROR, "transfer control to Standalone Boot Script Executor\r\n"));
844 SwitchStack (
845 (SWITCH_STACK_ENTRY_POINT) (UINTN) EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint,
846 (VOID *)AcpiS3Context,
847 (VOID *)PeiS3ResumeState,
848 (VOID *)(UINTN)(AcpiS3Context->BootScriptStackBase + AcpiS3Context->BootScriptStackSize)
849 );
850 }
851
852 //
853 // Never run to here
854 //
855 CpuDeadLoop();
856 }
857 /**
858 Restores the platform to its preboot configuration for an S3 resume and
859 jumps to the OS waking vector.
860
861 This function will restore the platform to its pre-boot configuration that was
862 pre-stored in the boot script table and transfer control to OS waking vector.
863 Upon invocation, this function is responsible for locating the following
864 information before jumping to OS waking vector:
865 - ACPI tables
866 - boot script table
867 - any other information that it needs
868
869 The S3RestoreConfig() function then executes the pre-stored boot script table
870 and transitions the platform to the pre-boot state. The boot script is recorded
871 during regular boot using the EFI_S3_SAVE_STATE_PROTOCOL.Write() and
872 EFI_S3_SMM_SAVE_STATE_PROTOCOL.Write() functions. Finally, this function
873 transfers control to the OS waking vector. If the OS supports only a real-mode
874 waking vector, this function will switch from flat mode to real mode before
875 jumping to the waking vector. If all platform pre-boot configurations are
876 successfully restored and all other necessary information is ready, this
877 function will never return and instead will directly jump to the OS waking
878 vector. If this function returns, it indicates that the attempt to resume
879 from the ACPI S3 sleep state failed.
880
881 @param[in] This Pointer to this instance of the PEI_S3_RESUME_PPI
882
883 @retval EFI_ABORTED Execution of the S3 resume boot script table failed.
884 @retval EFI_NOT_FOUND Some necessary information that is used for the S3
885 resume boot path could not be located.
886
887 **/
888 EFI_STATUS
889 EFIAPI
890 S3RestoreConfig2 (
891 IN EFI_PEI_S3_RESUME2_PPI *This
892 )
893 {
894 EFI_STATUS Status;
895 PEI_SMM_ACCESS_PPI *SmmAccess;
896 UINTN Index;
897 ACPI_S3_CONTEXT *AcpiS3Context;
898 EFI_PHYSICAL_ADDRESS TempEfiBootScriptExecutorVariable;
899 EFI_PHYSICAL_ADDRESS TempAcpiS3Context;
900 BOOT_SCRIPT_EXECUTOR_VARIABLE *EfiBootScriptExecutorVariable;
901 UINTN VarSize;
902 EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
903 SMM_S3_RESUME_STATE *SmmS3ResumeState;
904 VOID *GuidHob;
905 BOOLEAN Build4GPageTableOnly;
906 BOOLEAN InterruptStatus;
907
908 TempAcpiS3Context = 0;
909 TempEfiBootScriptExecutorVariable = 0;
910
911 DEBUG ((EFI_D_ERROR, "Enter S3 PEIM\r\n"));
912
913 VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
914 Status = RestoreLockBox (
915 &gEfiAcpiVariableGuid,
916 &TempAcpiS3Context,
917 &VarSize
918 );
919 ASSERT_EFI_ERROR (Status);
920
921 Status = RestoreLockBox (
922 &gEfiAcpiS3ContextGuid,
923 NULL,
924 NULL
925 );
926 ASSERT_EFI_ERROR (Status);
927
928 AcpiS3Context = (ACPI_S3_CONTEXT *)(UINTN)TempAcpiS3Context;
929 ASSERT (AcpiS3Context != NULL);
930
931 VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
932 Status = RestoreLockBox (
933 &gEfiBootScriptExecutorVariableGuid,
934 &TempEfiBootScriptExecutorVariable,
935 &VarSize
936 );
937 ASSERT_EFI_ERROR (Status);
938
939 Status = RestoreLockBox (
940 &gEfiBootScriptExecutorContextGuid,
941 NULL,
942 NULL
943 );
944 ASSERT_EFI_ERROR (Status);
945
946 EfiBootScriptExecutorVariable = (BOOT_SCRIPT_EXECUTOR_VARIABLE *) (UINTN) TempEfiBootScriptExecutorVariable;
947 ASSERT (EfiBootScriptExecutorVariable != NULL);
948
949 DEBUG (( EFI_D_ERROR, "AcpiS3Context = %x\n", AcpiS3Context));
950 DEBUG (( EFI_D_ERROR, "Waking Vector = %x\n", ((EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) ((UINTN) (AcpiS3Context->AcpiFacsTable)))->FirmwareWakingVector));
951 DEBUG (( EFI_D_ERROR, "AcpiS3Context->AcpiFacsTable = %x\n", AcpiS3Context->AcpiFacsTable));
952 DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3NvsPageTableAddress = %x\n", AcpiS3Context->S3NvsPageTableAddress));
953 DEBUG (( EFI_D_ERROR, "AcpiS3Context->S3DebugBufferAddress = %x\n", AcpiS3Context->S3DebugBufferAddress));
954 DEBUG (( EFI_D_ERROR, "EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint = %x\n", EfiBootScriptExecutorVariable->BootScriptExecutorEntrypoint));
955
956 //
957 // Additional step for BootScript integrity - we only handle BootScript and BootScriptExecutor.
958 // Script dispatch image and context (parameter) are handled by platform.
959 // We just use restore all lock box in place, no need restore one by one.
960 //
961 Status = RestoreAllLockBoxInPlace ();
962 ASSERT_EFI_ERROR (Status);
963 if (EFI_ERROR (Status)) {
964 // Something wrong
965 CpuDeadLoop ();
966 }
967
968 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
969 //
970 // Need reconstruct page table here, since we do not trust ACPINvs.
971 //
972 if (IsLongModeWakingVector (AcpiS3Context)) {
973 Build4GPageTableOnly = FALSE;
974 } else {
975 Build4GPageTableOnly = TRUE;
976 }
977 RestoreS3PageTables ((UINTN)AcpiS3Context->S3NvsPageTableAddress, Build4GPageTableOnly);
978 }
979
980 //
981 // Attempt to use content from SMRAM first
982 //
983 GuidHob = GetFirstGuidHob (&gEfiAcpiVariableGuid);
984 if (GuidHob != NULL) {
985 Status = PeiServicesLocatePpi (
986 &gPeiSmmAccessPpiGuid,
987 0,
988 NULL,
989 (VOID **) &SmmAccess
990 );
991 for (Index = 0; !EFI_ERROR (Status); Index++) {
992 Status = SmmAccess->Open ((EFI_PEI_SERVICES **)GetPeiServicesTablePointer (), SmmAccess, Index);
993 }
994
995 SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
996 SmmS3ResumeState = (SMM_S3_RESUME_STATE *)(UINTN)SmramDescriptor->CpuStart;
997
998 SmmS3ResumeState->ReturnCs = AsmReadCs ();
999 SmmS3ResumeState->ReturnEntryPoint = (EFI_PHYSICAL_ADDRESS)(UINTN)S3ResumeExecuteBootScript;
1000 SmmS3ResumeState->ReturnContext1 = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
1001 SmmS3ResumeState->ReturnContext2 = (EFI_PHYSICAL_ADDRESS)(UINTN)EfiBootScriptExecutorVariable;
1002 SmmS3ResumeState->ReturnStackPointer = (EFI_PHYSICAL_ADDRESS)(UINTN)&Status;
1003
1004 DEBUG (( EFI_D_ERROR, "SMM S3 Signature = %x\n", SmmS3ResumeState->Signature));
1005 DEBUG (( EFI_D_ERROR, "SMM S3 Stack Base = %x\n", SmmS3ResumeState->SmmS3StackBase));
1006 DEBUG (( EFI_D_ERROR, "SMM S3 Stack Size = %x\n", SmmS3ResumeState->SmmS3StackSize));
1007 DEBUG (( EFI_D_ERROR, "SMM S3 Resume Entry Point = %x\n", SmmS3ResumeState->SmmS3ResumeEntryPoint));
1008 DEBUG (( EFI_D_ERROR, "SMM S3 CR0 = %x\n", SmmS3ResumeState->SmmS3Cr0));
1009 DEBUG (( EFI_D_ERROR, "SMM S3 CR3 = %x\n", SmmS3ResumeState->SmmS3Cr3));
1010 DEBUG (( EFI_D_ERROR, "SMM S3 CR4 = %x\n", SmmS3ResumeState->SmmS3Cr4));
1011 DEBUG (( EFI_D_ERROR, "SMM S3 Return CS = %x\n", SmmS3ResumeState->ReturnCs));
1012 DEBUG (( EFI_D_ERROR, "SMM S3 Return Entry Point = %x\n", SmmS3ResumeState->ReturnEntryPoint));
1013 DEBUG (( EFI_D_ERROR, "SMM S3 Return Context1 = %x\n", SmmS3ResumeState->ReturnContext1));
1014 DEBUG (( EFI_D_ERROR, "SMM S3 Return Context2 = %x\n", SmmS3ResumeState->ReturnContext2));
1015 DEBUG (( EFI_D_ERROR, "SMM S3 Return Stack Pointer = %x\n", SmmS3ResumeState->ReturnStackPointer));
1016 DEBUG (( EFI_D_ERROR, "SMM S3 Smst = %x\n", SmmS3ResumeState->Smst));
1017
1018 if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_32) {
1019 SwitchStack (
1020 (SWITCH_STACK_ENTRY_POINT)(UINTN)SmmS3ResumeState->SmmS3ResumeEntryPoint,
1021 (VOID *)AcpiS3Context,
1022 0,
1023 (VOID *)(UINTN)(SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize)
1024 );
1025 }
1026 if (SmmS3ResumeState->Signature == SMM_S3_RESUME_SMM_64) {
1027 //
1028 // Switch to long mode to complete resume.
1029 //
1030
1031 InterruptStatus = SaveAndDisableInterrupts ();
1032 //
1033 // Need to make sure the GDT is loaded with values that support long mode and real mode.
1034 //
1035 AsmWriteGdtr (&mGdt);
1036 //
1037 // update segment selectors per the new GDT.
1038 //
1039 AsmSetDataSelectors (DATA_SEGEMENT_SELECTOR);
1040 //
1041 // Restore interrupt state.
1042 //
1043 SetInterruptState (InterruptStatus);
1044
1045 AsmWriteCr3 ((UINTN)SmmS3ResumeState->SmmS3Cr3);
1046
1047 //
1048 // Disable interrupt of Debug timer, since IDT table cannot work in long mode.
1049 // NOTE: On x64 platforms, because DisablePaging64() will disable interrupts,
1050 // the code in S3ResumeExecuteBootScript() cannot be halted by soft debugger.
1051 //
1052 SaveAndSetDebugTimerInterrupt (FALSE);
1053
1054 AsmEnablePaging64 (
1055 0x38,
1056 SmmS3ResumeState->SmmS3ResumeEntryPoint,
1057 (UINT64)(UINTN)AcpiS3Context,
1058 0,
1059 SmmS3ResumeState->SmmS3StackBase + SmmS3ResumeState->SmmS3StackSize
1060 );
1061 }
1062
1063 }
1064
1065 S3ResumeExecuteBootScript (AcpiS3Context, EfiBootScriptExecutorVariable );
1066 return EFI_SUCCESS;
1067 }
1068 /**
1069 Main entry for S3 Resume PEIM.
1070
1071 This routine is to install EFI_PEI_S3_RESUME2_PPI.
1072
1073 @param FileHandle Handle of the file being invoked.
1074 @param PeiServices Pointer to PEI Services table.
1075
1076 @retval EFI_SUCCESS S3Resume Ppi is installed successfully.
1077
1078 **/
1079 EFI_STATUS
1080 EFIAPI
1081 PeimS3ResumeEntryPoint (
1082 IN EFI_PEI_FILE_HANDLE FileHandle,
1083 IN CONST EFI_PEI_SERVICES **PeiServices
1084 )
1085 {
1086 EFI_STATUS Status;
1087
1088 //
1089 // Install S3 Resume Ppi
1090 //
1091 Status = (**PeiServices).InstallPpi (PeiServices, &mPpiList);
1092 ASSERT_EFI_ERROR (Status);
1093
1094 return EFI_SUCCESS;
1095 }
1096