S3Resume.c 42 KB

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