]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Universal/Acpi/S3Resume2Pei/S3Resume.c
Correct INF file to make module pass ICC compiler.
[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 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