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