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