]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Universal / Acpi / S3SaveStateDxe / AcpiS3ContextSave.c
CommitLineData
bd890a73
SZ
1/** @file\r
2 This is the implementation to save ACPI S3 Context.\r
3\r
8bd2028f 4Copyright (c) 2006 - 2022, Intel Corporation. All rights reserved.<BR>\r
bd890a73 5\r
9d510e61 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
bd890a73
SZ
7\r
8**/\r
9\r
10#include <PiDxe.h>\r
11#include <Library/BaseLib.h>\r
12#include <Library/BaseMemoryLib.h>\r
13#include <Library/UefiBootServicesTableLib.h>\r
14#include <Library/HobLib.h>\r
15#include <Library/LockBoxLib.h>\r
16#include <Library/PcdLib.h>\r
17#include <Library/DebugLib.h>\r
2ad0581b 18#include <Library/UefiLib.h>\r
bd890a73 19#include <Guid/AcpiS3Context.h>\r
bd890a73
SZ
20#include <IndustryStandard/Acpi.h>\r
21#include <Protocol/LockBox.h>\r
22\r
23//\r
24// 8 extra pages for PF handler.\r
25//\r
1436aea4 26#define EXTRA_PAGE_TABLE_PAGES 8\r
bd890a73 27\r
1436aea4 28EFI_GUID mAcpiS3IdtrProfileGuid = {\r
bd890a73
SZ
29 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }\r
30};\r
31\r
32/**\r
33 Allocate memory below 4G memory address.\r
34\r
35 This function allocates memory below 4G memory address.\r
36\r
37 @param MemoryType Memory type of memory to allocate.\r
38 @param Size Size of memory to allocate.\r
d1102dba 39\r
bd890a73
SZ
40 @return Allocated address for output.\r
41\r
42**/\r
1436aea4 43VOID *\r
bd890a73 44AllocateMemoryBelow4G (\r
1436aea4
MK
45 IN EFI_MEMORY_TYPE MemoryType,\r
46 IN UINTN Size\r
bd890a73
SZ
47 )\r
48{\r
49 UINTN Pages;\r
50 EFI_PHYSICAL_ADDRESS Address;\r
51 EFI_STATUS Status;\r
1436aea4 52 VOID *Buffer;\r
bd890a73 53\r
1436aea4 54 Pages = EFI_SIZE_TO_PAGES (Size);\r
bd890a73
SZ
55 Address = 0xffffffff;\r
56\r
1436aea4
MK
57 Status = gBS->AllocatePages (\r
58 AllocateMaxAddress,\r
59 MemoryType,\r
60 Pages,\r
61 &Address\r
62 );\r
bd890a73
SZ
63 ASSERT_EFI_ERROR (Status);\r
64\r
1436aea4 65 Buffer = (VOID *)(UINTN)Address;\r
bd890a73
SZ
66 ZeroMem (Buffer, Size);\r
67\r
68 return Buffer;\r
69}\r
70\r
bd890a73
SZ
71/**\r
72 The function will check if long mode waking vector is supported.\r
73\r
74 @param[in] Facs Pointer to FACS table.\r
75\r
76 @retval TRUE Long mode waking vector is supported.\r
77 @retval FALSE Long mode waking vector is not supported.\r
78\r
79**/\r
80BOOLEAN\r
81IsLongModeWakingVectorSupport (\r
1436aea4 82 IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs\r
bd890a73
SZ
83 )\r
84{\r
85 if ((Facs == NULL) ||\r
1436aea4
MK
86 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE))\r
87 {\r
bd890a73
SZ
88 //\r
89 // Something wrong with FACS.\r
90 //\r
91 return FALSE;\r
92 }\r
1436aea4 93\r
bd890a73 94 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
1436aea4
MK
95 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0))\r
96 {\r
bd890a73
SZ
97 //\r
98 // BIOS supports 64bit waking vector.\r
99 //\r
8bd2028f 100 if (sizeof (UINTN) == sizeof (UINT64)) {\r
bd890a73
SZ
101 return TRUE;\r
102 }\r
103 }\r
1436aea4 104\r
bd890a73
SZ
105 return FALSE;\r
106}\r
107\r
108/**\r
109 Allocates page table buffer.\r
110\r
111 @param[in] LongModeWakingVectorSupport Support long mode waking vector or not.\r
112\r
8bd2028f 113 If BootScriptExecutor driver will run in 64-bit mode, this function will establish the 1:1\r
bd890a73
SZ
114 virtual to physical mapping page table when long mode waking vector is supported, otherwise\r
115 create 4G page table when long mode waking vector is not supported and let PF handler to\r
116 handle > 4G request.\r
8bd2028f 117 If BootScriptExecutor driver will not run in 64-bit mode, this function will do nothing.\r
d1102dba
LG
118\r
119 @return Page table base address.\r
bd890a73
SZ
120\r
121**/\r
122EFI_PHYSICAL_ADDRESS\r
123S3AllocatePageTablesBuffer (\r
1436aea4 124 IN BOOLEAN LongModeWakingVectorSupport\r
bd890a73 125 )\r
d1102dba 126{\r
8bd2028f 127 if ((FeaturePcdGet (PcdDxeIplSwitchToLongMode)) || (sizeof (UINTN) == sizeof (UINT64))) {\r
1436aea4
MK
128 UINTN ExtraPageTablePages;\r
129 UINT32 RegEax;\r
130 UINT32 RegEdx;\r
131 UINT8 PhysicalAddressBits;\r
132 UINT32 NumberOfPml4EntriesNeeded;\r
133 UINT32 NumberOfPdpEntriesNeeded;\r
134 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;\r
135 UINTN TotalPageTableSize;\r
136 VOID *Hob;\r
137 BOOLEAN Page1GSupport;\r
bd890a73
SZ
138\r
139 Page1GSupport = FALSE;\r
1436aea4 140 if (PcdGetBool (PcdUse1GPageTable)) {\r
bd890a73
SZ
141 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
142 if (RegEax >= 0x80000001) {\r
143 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
144 if ((RegEdx & BIT26) != 0) {\r
145 Page1GSupport = TRUE;\r
146 }\r
147 }\r
148 }\r
149\r
150 //\r
151 // Get physical address bits supported.\r
152 //\r
153 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
154 if (Hob != NULL) {\r
1436aea4 155 PhysicalAddressBits = ((EFI_HOB_CPU *)Hob)->SizeOfMemorySpace;\r
bd890a73
SZ
156 } else {\r
157 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
158 if (RegEax >= 0x80000008) {\r
159 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
1436aea4 160 PhysicalAddressBits = (UINT8)RegEax;\r
bd890a73
SZ
161 } else {\r
162 PhysicalAddressBits = 36;\r
163 }\r
164 }\r
165\r
166 //\r
167 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
168 //\r
169 ASSERT (PhysicalAddressBits <= 52);\r
170 if (PhysicalAddressBits > 48) {\r
171 PhysicalAddressBits = 48;\r
172 }\r
173\r
174 ExtraPageTablePages = 0;\r
175 if (!LongModeWakingVectorSupport) {\r
176 //\r
177 // Create 4G page table when BIOS does not support long mode waking vector,\r
178 // and let PF handler to handle > 4G request.\r
179 //\r
180 PhysicalAddressBits = 32;\r
181 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
182 }\r
183\r
184 //\r
185 // Calculate the table entries needed.\r
186 //\r
187 if (PhysicalAddressBits <= 39 ) {\r
188 NumberOfPml4EntriesNeeded = 1;\r
1436aea4 189 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
bd890a73
SZ
190 } else {\r
191 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
1436aea4 192 NumberOfPdpEntriesNeeded = 512;\r
bd890a73
SZ
193 }\r
194\r
195 //\r
196 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.\r
197 //\r
198 if (!Page1GSupport) {\r
16f69227 199 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded;\r
bd890a73 200 } else {\r
16f69227 201 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded;\r
bd890a73
SZ
202 }\r
203\r
204 TotalPageTableSize += ExtraPageTablePages;\r
558f58e3 205 DEBUG ((DEBUG_INFO, "AcpiS3ContextSave TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));\r
bd890a73
SZ
206\r
207 //\r
208 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
209 //\r
1436aea4 210 S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE (TotalPageTableSize));\r
bd890a73
SZ
211 ASSERT (S3NvsPageTableAddress != 0);\r
212 return S3NvsPageTableAddress;\r
213 } else {\r
214 //\r
215 // If DXE is running 32-bit mode, no need to establish page table.\r
216 //\r
1436aea4 217 return (EFI_PHYSICAL_ADDRESS)0;\r
bd890a73
SZ
218 }\r
219}\r
220\r
221/**\r
222 Callback function executed when the EndOfDxe event group is signaled.\r
223\r
224 @param[in] Event Event whose notification function is being invoked.\r
225 @param[in] Context The pointer to the notification function's context, which\r
226 is implementation-dependent.\r
227**/\r
228VOID\r
229EFIAPI\r
230AcpiS3ContextSaveOnEndOfDxe (\r
231 IN EFI_EVENT Event,\r
232 IN VOID *Context\r
233 )\r
234{\r
235 EFI_STATUS Status;\r
236 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;\r
237 ACPI_S3_CONTEXT *AcpiS3Context;\r
238 IA32_DESCRIPTOR *Idtr;\r
239 IA32_IDT_GATE_DESCRIPTOR *IdtGate;\r
240 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
241 VOID *Interface;\r
242\r
87000d77 243 DEBUG ((DEBUG_INFO, "AcpiS3ContextSave!\n"));\r
bd890a73
SZ
244\r
245 Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);\r
246 if (EFI_ERROR (Status)) {\r
87000d77 247 DEBUG ((DEBUG_INFO | DEBUG_WARN, "ACPI S3 context can't be saved without LockBox!\n"));\r
bd890a73
SZ
248 goto Done;\r
249 }\r
250\r
1436aea4 251 AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof (*AcpiS3Context));\r
bd890a73
SZ
252 ASSERT (AcpiS3Context != NULL);\r
253 AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
254\r
255 //\r
256 // Get ACPI Table because we will save its position to variable\r
257 //\r
1436aea4
MK
258 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)EfiLocateFirstAcpiTable (\r
259 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE\r
260 );\r
261 AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)Facs;\r
bd890a73
SZ
262 ASSERT (AcpiS3Context->AcpiFacsTable != 0);\r
263\r
1436aea4
MK
264 IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof (IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof (IA32_DESCRIPTOR));\r
265 Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);\r
266 Idtr->Base = (UINTN)IdtGate;\r
267 Idtr->Limit = (UINT16)(sizeof (IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);\r
bd890a73
SZ
268 AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;\r
269\r
270 Status = SaveLockBox (\r
271 &mAcpiS3IdtrProfileGuid,\r
272 (VOID *)(UINTN)Idtr,\r
1436aea4 273 (UINTN)sizeof (IA32_DESCRIPTOR)\r
bd890a73
SZ
274 );\r
275 ASSERT_EFI_ERROR (Status);\r
276\r
277 Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
278 ASSERT_EFI_ERROR (Status);\r
279\r
280 //\r
281 // Allocate page table\r
282 //\r
283 AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));\r
284\r
285 //\r
286 // Allocate stack\r
287 //\r
288 AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);\r
289 AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));\r
290 ASSERT (AcpiS3Context->BootScriptStackBase != 0);\r
291\r
292 //\r
293 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.\r
294 //\r
295 AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);\r
296 SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);\r
297\r
1436aea4
MK
298 DEBUG ((DEBUG_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));\r
299 DEBUG ((DEBUG_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));\r
300 DEBUG ((DEBUG_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));\r
301 DEBUG ((DEBUG_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));\r
302 DEBUG ((DEBUG_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));\r
303 DEBUG ((DEBUG_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));\r
bd890a73
SZ
304\r
305 Status = SaveLockBox (\r
306 &gEfiAcpiVariableGuid,\r
307 &AcpiS3ContextBuffer,\r
1436aea4 308 sizeof (AcpiS3ContextBuffer)\r
bd890a73
SZ
309 );\r
310 ASSERT_EFI_ERROR (Status);\r
311\r
312 Status = SaveLockBox (\r
313 &gEfiAcpiS3ContextGuid,\r
314 (VOID *)(UINTN)AcpiS3Context,\r
1436aea4 315 (UINTN)sizeof (*AcpiS3Context)\r
bd890a73
SZ
316 );\r
317 ASSERT_EFI_ERROR (Status);\r
318\r
319 Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
320 ASSERT_EFI_ERROR (Status);\r
321\r
322Done:\r
323 //\r
324 // Close the event, deregistering the callback and freeing resources.\r
325 //\r
326 Status = gBS->CloseEvent (Event);\r
327 ASSERT_EFI_ERROR (Status);\r
328}\r