1 | /** @file
|
---|
2 | This is an implementation of the ACPI S3 Save protocol. This is defined in
|
---|
3 | S3 boot path specification 0.9.
|
---|
4 |
|
---|
5 | Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
|
---|
6 |
|
---|
7 | This program and the accompanying materials
|
---|
8 | are licensed and made available under the terms and conditions
|
---|
9 | of the BSD License which accompanies this distribution. The
|
---|
10 | full text of the license may be found at
|
---|
11 | http://opensource.org/licenses/bsd-license.php
|
---|
12 |
|
---|
13 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
14 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
15 |
|
---|
16 | **/
|
---|
17 |
|
---|
18 | #include <PiDxe.h>
|
---|
19 | #include <Library/BaseLib.h>
|
---|
20 | #include <Library/BaseMemoryLib.h>
|
---|
21 | #include <Library/UefiBootServicesTableLib.h>
|
---|
22 | #include <Library/UefiRuntimeServicesTableLib.h>
|
---|
23 | #include <Library/HobLib.h>
|
---|
24 | #include <Library/LockBoxLib.h>
|
---|
25 | #include <Library/PcdLib.h>
|
---|
26 | #include <Library/DebugLib.h>
|
---|
27 | #include <Library/QemuFwCfgLib.h>
|
---|
28 | #include <Guid/AcpiVariableCompatibility.h>
|
---|
29 | #include <Guid/AcpiS3Context.h>
|
---|
30 | #include <Guid/Acpi.h>
|
---|
31 | #include <Protocol/AcpiS3Save.h>
|
---|
32 | #include <Protocol/S3SaveState.h>
|
---|
33 | #include <Protocol/DxeSmmReadyToLock.h>
|
---|
34 | #include <Protocol/LockBox.h>
|
---|
35 | #include <IndustryStandard/Acpi.h>
|
---|
36 |
|
---|
37 | #include "AcpiS3Save.h"
|
---|
38 |
|
---|
39 | UINTN mLegacyRegionSize;
|
---|
40 |
|
---|
41 | EFI_ACPI_S3_SAVE_PROTOCOL mS3Save = {
|
---|
42 | LegacyGetS3MemorySize,
|
---|
43 | S3Ready,
|
---|
44 | };
|
---|
45 |
|
---|
46 | EFI_GUID mAcpiS3IdtrProfileGuid = {
|
---|
47 | 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
|
---|
48 | };
|
---|
49 |
|
---|
50 | /**
|
---|
51 | Allocate memory below 4G memory address.
|
---|
52 |
|
---|
53 | This function allocates memory below 4G memory address.
|
---|
54 |
|
---|
55 | @param MemoryType Memory type of memory to allocate.
|
---|
56 | @param Size Size of memory to allocate.
|
---|
57 |
|
---|
58 | @return Allocated address for output.
|
---|
59 |
|
---|
60 | **/
|
---|
61 | VOID*
|
---|
62 | AllocateMemoryBelow4G (
|
---|
63 | IN EFI_MEMORY_TYPE MemoryType,
|
---|
64 | IN UINTN Size
|
---|
65 | )
|
---|
66 | {
|
---|
67 | UINTN Pages;
|
---|
68 | EFI_PHYSICAL_ADDRESS Address;
|
---|
69 | EFI_STATUS Status;
|
---|
70 | VOID* Buffer;
|
---|
71 |
|
---|
72 | Pages = EFI_SIZE_TO_PAGES (Size);
|
---|
73 | Address = 0xffffffff;
|
---|
74 |
|
---|
75 | Status = gBS->AllocatePages (
|
---|
76 | AllocateMaxAddress,
|
---|
77 | MemoryType,
|
---|
78 | Pages,
|
---|
79 | &Address
|
---|
80 | );
|
---|
81 | ASSERT_EFI_ERROR (Status);
|
---|
82 |
|
---|
83 | Buffer = (VOID *) (UINTN) Address;
|
---|
84 | ZeroMem (Buffer, Size);
|
---|
85 |
|
---|
86 | return Buffer;
|
---|
87 | }
|
---|
88 |
|
---|
89 | /**
|
---|
90 |
|
---|
91 | This function scan ACPI table in RSDT.
|
---|
92 |
|
---|
93 | @param Rsdt ACPI RSDT
|
---|
94 | @param Signature ACPI table signature
|
---|
95 |
|
---|
96 | @return ACPI table
|
---|
97 |
|
---|
98 | **/
|
---|
99 | VOID *
|
---|
100 | ScanTableInRSDT (
|
---|
101 | IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
|
---|
102 | IN UINT32 Signature
|
---|
103 | )
|
---|
104 | {
|
---|
105 | UINTN Index;
|
---|
106 | UINT32 EntryCount;
|
---|
107 | UINT32 *EntryPtr;
|
---|
108 | EFI_ACPI_DESCRIPTION_HEADER *Table;
|
---|
109 |
|
---|
110 | if (Rsdt == NULL) {
|
---|
111 | return NULL;
|
---|
112 | }
|
---|
113 |
|
---|
114 | EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
|
---|
115 |
|
---|
116 | EntryPtr = (UINT32 *)(Rsdt + 1);
|
---|
117 | for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
|
---|
118 | Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
|
---|
119 | if (Table->Signature == Signature) {
|
---|
120 | return Table;
|
---|
121 | }
|
---|
122 | }
|
---|
123 |
|
---|
124 | return NULL;
|
---|
125 | }
|
---|
126 |
|
---|
127 | /**
|
---|
128 |
|
---|
129 | This function scan ACPI table in XSDT.
|
---|
130 |
|
---|
131 | @param Xsdt ACPI XSDT
|
---|
132 | @param Signature ACPI table signature
|
---|
133 |
|
---|
134 | @return ACPI table
|
---|
135 |
|
---|
136 | **/
|
---|
137 | VOID *
|
---|
138 | ScanTableInXSDT (
|
---|
139 | IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
|
---|
140 | IN UINT32 Signature
|
---|
141 | )
|
---|
142 | {
|
---|
143 | UINTN Index;
|
---|
144 | UINT32 EntryCount;
|
---|
145 | UINT64 EntryPtr;
|
---|
146 | UINTN BasePtr;
|
---|
147 | EFI_ACPI_DESCRIPTION_HEADER *Table;
|
---|
148 |
|
---|
149 | if (Xsdt == NULL) {
|
---|
150 | return NULL;
|
---|
151 | }
|
---|
152 |
|
---|
153 | EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
|
---|
154 |
|
---|
155 | BasePtr = (UINTN)(Xsdt + 1);
|
---|
156 | for (Index = 0; Index < EntryCount; Index ++) {
|
---|
157 | CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
|
---|
158 | Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
|
---|
159 | if (Table->Signature == Signature) {
|
---|
160 | return Table;
|
---|
161 | }
|
---|
162 | }
|
---|
163 |
|
---|
164 | return NULL;
|
---|
165 | }
|
---|
166 |
|
---|
167 | /**
|
---|
168 | To find Facs in FADT.
|
---|
169 |
|
---|
170 | @param Fadt FADT table pointer
|
---|
171 |
|
---|
172 | @return Facs table pointer.
|
---|
173 | **/
|
---|
174 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
|
---|
175 | FindAcpiFacsFromFadt (
|
---|
176 | IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt
|
---|
177 | )
|
---|
178 | {
|
---|
179 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
---|
180 | UINT64 Data64;
|
---|
181 |
|
---|
182 | if (Fadt == NULL) {
|
---|
183 | return NULL;
|
---|
184 | }
|
---|
185 |
|
---|
186 | if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
|
---|
187 | Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
|
---|
188 | } else {
|
---|
189 | if (Fadt->FirmwareCtrl != 0) {
|
---|
190 | Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
|
---|
191 | } else {
|
---|
192 | CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
|
---|
193 | Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
|
---|
194 | }
|
---|
195 | }
|
---|
196 | return Facs;
|
---|
197 | }
|
---|
198 |
|
---|
199 | /**
|
---|
200 | To find Facs in Acpi tables.
|
---|
201 |
|
---|
202 | To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
|
---|
203 | in the table.
|
---|
204 |
|
---|
205 | @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
|
---|
206 |
|
---|
207 | @return Facs table pointer.
|
---|
208 | **/
|
---|
209 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
|
---|
210 | FindAcpiFacsTableByAcpiGuid (
|
---|
211 | IN EFI_GUID *AcpiTableGuid
|
---|
212 | )
|
---|
213 | {
|
---|
214 | EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
|
---|
215 | EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
|
---|
216 | EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
|
---|
217 | EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
|
---|
218 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
---|
219 | UINTN Index;
|
---|
220 |
|
---|
221 | Rsdp = NULL;
|
---|
222 | //
|
---|
223 | // found ACPI table RSD_PTR from system table
|
---|
224 | //
|
---|
225 | for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
|
---|
226 | if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
|
---|
227 | //
|
---|
228 | // A match was found.
|
---|
229 | //
|
---|
230 | Rsdp = gST->ConfigurationTable[Index].VendorTable;
|
---|
231 | break;
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | if (Rsdp == NULL) {
|
---|
236 | return NULL;
|
---|
237 | }
|
---|
238 |
|
---|
239 | //
|
---|
240 | // Search XSDT
|
---|
241 | //
|
---|
242 | if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
|
---|
243 | Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
|
---|
244 | Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
|
---|
245 | if (Fadt != NULL) {
|
---|
246 | Facs = FindAcpiFacsFromFadt (Fadt);
|
---|
247 | if (Facs != NULL) {
|
---|
248 | return Facs;
|
---|
249 | }
|
---|
250 | }
|
---|
251 | }
|
---|
252 |
|
---|
253 | //
|
---|
254 | // Search RSDT
|
---|
255 | //
|
---|
256 | Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
|
---|
257 | Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
|
---|
258 | if (Fadt != NULL) {
|
---|
259 | Facs = FindAcpiFacsFromFadt (Fadt);
|
---|
260 | if (Facs != NULL) {
|
---|
261 | return Facs;
|
---|
262 | }
|
---|
263 | }
|
---|
264 |
|
---|
265 | return NULL;
|
---|
266 | }
|
---|
267 |
|
---|
268 | /**
|
---|
269 | To find Facs in Acpi tables.
|
---|
270 |
|
---|
271 | To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
|
---|
272 | in the table.
|
---|
273 |
|
---|
274 | @return Facs table pointer.
|
---|
275 | **/
|
---|
276 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
|
---|
277 | FindAcpiFacsTable (
|
---|
278 | VOID
|
---|
279 | )
|
---|
280 | {
|
---|
281 | EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
|
---|
282 |
|
---|
283 | Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);
|
---|
284 | if (Facs != NULL) {
|
---|
285 | return Facs;
|
---|
286 | }
|
---|
287 |
|
---|
288 | return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);
|
---|
289 | }
|
---|
290 |
|
---|
291 | /**
|
---|
292 | Allocates and fills in the Page Directory and Page Table Entries to
|
---|
293 | establish a 1:1 Virtual to Physical mapping.
|
---|
294 | If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
|
---|
295 | virtual to physical mapping page table.
|
---|
296 | If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
|
---|
297 |
|
---|
298 | @return the 1:1 Virtual to Physical identity mapping page table base address.
|
---|
299 |
|
---|
300 | **/
|
---|
301 | EFI_PHYSICAL_ADDRESS
|
---|
302 | S3CreateIdentityMappingPageTables (
|
---|
303 | VOID
|
---|
304 | )
|
---|
305 | {
|
---|
306 | if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
|
---|
307 | UINT32 RegEax;
|
---|
308 | UINT32 RegEdx;
|
---|
309 | UINT8 PhysicalAddressBits;
|
---|
310 | UINT32 NumberOfPml4EntriesNeeded;
|
---|
311 | UINT32 NumberOfPdpEntriesNeeded;
|
---|
312 | EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
|
---|
313 | UINTN TotalPageTableSize;
|
---|
314 | VOID *Hob;
|
---|
315 | BOOLEAN Page1GSupport;
|
---|
316 |
|
---|
317 | Page1GSupport = FALSE;
|
---|
318 | if (PcdGetBool(PcdUse1GPageTable)) {
|
---|
319 | AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
---|
320 | if (RegEax >= 0x80000001) {
|
---|
321 | AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
|
---|
322 | if ((RegEdx & BIT26) != 0) {
|
---|
323 | Page1GSupport = TRUE;
|
---|
324 | }
|
---|
325 | }
|
---|
326 | }
|
---|
327 |
|
---|
328 | //
|
---|
329 | // Get physical address bits supported.
|
---|
330 | //
|
---|
331 | Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
|
---|
332 | if (Hob != NULL) {
|
---|
333 | PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
|
---|
334 | } else {
|
---|
335 | AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
|
---|
336 | if (RegEax >= 0x80000008) {
|
---|
337 | AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
|
---|
338 | PhysicalAddressBits = (UINT8) RegEax;
|
---|
339 | } else {
|
---|
340 | PhysicalAddressBits = 36;
|
---|
341 | }
|
---|
342 | }
|
---|
343 |
|
---|
344 | //
|
---|
345 | // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
|
---|
346 | //
|
---|
347 | ASSERT (PhysicalAddressBits <= 52);
|
---|
348 | if (PhysicalAddressBits > 48) {
|
---|
349 | PhysicalAddressBits = 48;
|
---|
350 | }
|
---|
351 |
|
---|
352 | //
|
---|
353 | // Calculate the table entries needed.
|
---|
354 | //
|
---|
355 | if (PhysicalAddressBits <= 39 ) {
|
---|
356 | NumberOfPml4EntriesNeeded = 1;
|
---|
357 | NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
|
---|
358 | } else {
|
---|
359 | NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
|
---|
360 | NumberOfPdpEntriesNeeded = 512;
|
---|
361 | }
|
---|
362 |
|
---|
363 | //
|
---|
364 | // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
|
---|
365 | //
|
---|
366 | if (!Page1GSupport) {
|
---|
367 | TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);
|
---|
368 | } else {
|
---|
369 | TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded);
|
---|
370 | }
|
---|
371 | DEBUG ((EFI_D_ERROR, "TotalPageTableSize - %x pages\n", TotalPageTableSize));
|
---|
372 |
|
---|
373 | //
|
---|
374 | // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
|
---|
375 | //
|
---|
376 | S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
|
---|
377 | ASSERT (S3NvsPageTableAddress != 0);
|
---|
378 | return S3NvsPageTableAddress;
|
---|
379 | } else {
|
---|
380 | //
|
---|
381 | // If DXE is running 32-bit mode, no need to establish page table.
|
---|
382 | //
|
---|
383 | return (EFI_PHYSICAL_ADDRESS) 0;
|
---|
384 | }
|
---|
385 | }
|
---|
386 |
|
---|
387 | /**
|
---|
388 | Gets the buffer of legacy memory below 1 MB
|
---|
389 | This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
|
---|
390 |
|
---|
391 | @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
|
---|
392 | @param Size The returned size of legacy memory below 1 MB.
|
---|
393 |
|
---|
394 | @retval EFI_SUCCESS Size is successfully returned.
|
---|
395 | @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
|
---|
396 |
|
---|
397 | **/
|
---|
398 | EFI_STATUS
|
---|
399 | EFIAPI
|
---|
400 | LegacyGetS3MemorySize (
|
---|
401 | IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
|
---|
402 | OUT UINTN *Size
|
---|
403 | )
|
---|
404 | {
|
---|
405 | if (Size == NULL) {
|
---|
406 | return EFI_INVALID_PARAMETER;
|
---|
407 | }
|
---|
408 |
|
---|
409 | *Size = mLegacyRegionSize;
|
---|
410 | return EFI_SUCCESS;
|
---|
411 | }
|
---|
412 |
|
---|
413 | /**
|
---|
414 | Save the S3 boot script.
|
---|
415 |
|
---|
416 | Note that we trigger DxeSmmReadyToLock here -- otherwise the script wouldn't
|
---|
417 | be saved actually. Triggering this protocol installation event in turn locks
|
---|
418 | down SMM, so no further changes to LockBoxes or SMRAM are possible
|
---|
419 | afterwards.
|
---|
420 | **/
|
---|
421 | STATIC
|
---|
422 | VOID
|
---|
423 | EFIAPI
|
---|
424 | SaveS3BootScript (
|
---|
425 | VOID
|
---|
426 | )
|
---|
427 | {
|
---|
428 | EFI_STATUS Status;
|
---|
429 | EFI_S3_SAVE_STATE_PROTOCOL *BootScript;
|
---|
430 | EFI_HANDLE Handle;
|
---|
431 | STATIC CONST UINT8 Info[] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
---|
432 |
|
---|
433 | Status = gBS->LocateProtocol (&gEfiS3SaveStateProtocolGuid, NULL,
|
---|
434 | (VOID **) &BootScript);
|
---|
435 | ASSERT_EFI_ERROR (Status);
|
---|
436 |
|
---|
437 | //
|
---|
438 | // Despite the opcode documentation in the PI spec, the protocol
|
---|
439 | // implementation embeds a deep copy of the info in the boot script, rather
|
---|
440 | // than storing just a pointer to runtime or NVS storage.
|
---|
441 | //
|
---|
442 | Status = BootScript->Write(BootScript, EFI_BOOT_SCRIPT_INFORMATION_OPCODE,
|
---|
443 | (UINT32) sizeof Info,
|
---|
444 | (EFI_PHYSICAL_ADDRESS)(UINTN) &Info);
|
---|
445 | ASSERT_EFI_ERROR (Status);
|
---|
446 |
|
---|
447 | Handle = NULL;
|
---|
448 | Status = gBS->InstallProtocolInterface (&Handle,
|
---|
449 | &gEfiDxeSmmReadyToLockProtocolGuid, EFI_NATIVE_INTERFACE,
|
---|
450 | NULL);
|
---|
451 | ASSERT_EFI_ERROR (Status);
|
---|
452 | }
|
---|
453 |
|
---|
454 |
|
---|
455 | /**
|
---|
456 | Prepares all information that is needed in the S3 resume boot path.
|
---|
457 |
|
---|
458 | Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
|
---|
459 |
|
---|
460 | @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
|
---|
461 | @param LegacyMemoryAddress The base address of legacy memory.
|
---|
462 |
|
---|
463 | @retval EFI_NOT_FOUND Some necessary information cannot be found.
|
---|
464 | @retval EFI_SUCCESS All information was saved successfully.
|
---|
465 | @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information.
|
---|
466 | @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
|
---|
467 |
|
---|
468 | **/
|
---|
469 | EFI_STATUS
|
---|
470 | EFIAPI
|
---|
471 | S3Ready (
|
---|
472 | IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
|
---|
473 | IN VOID *LegacyMemoryAddress
|
---|
474 | )
|
---|
475 | {
|
---|
476 | EFI_STATUS Status;
|
---|
477 | EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
|
---|
478 | ACPI_S3_CONTEXT *AcpiS3Context;
|
---|
479 | STATIC BOOLEAN AlreadyEntered;
|
---|
480 | IA32_DESCRIPTOR *Idtr;
|
---|
481 | IA32_IDT_GATE_DESCRIPTOR *IdtGate;
|
---|
482 |
|
---|
483 | DEBUG ((EFI_D_INFO, "S3Ready!\n"));
|
---|
484 |
|
---|
485 | //
|
---|
486 | // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
|
---|
487 | // So if 2nd S3Save() is triggered later, we need ignore it.
|
---|
488 | //
|
---|
489 | if (AlreadyEntered) {
|
---|
490 | return EFI_SUCCESS;
|
---|
491 | }
|
---|
492 | AlreadyEntered = TRUE;
|
---|
493 |
|
---|
494 | AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
|
---|
495 | ASSERT (AcpiS3Context != NULL);
|
---|
496 | AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
|
---|
497 |
|
---|
498 | //
|
---|
499 | // Get ACPI Table because we will save its position to variable
|
---|
500 | //
|
---|
501 | AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS)(UINTN)FindAcpiFacsTable ();
|
---|
502 | ASSERT (AcpiS3Context->AcpiFacsTable != 0);
|
---|
503 |
|
---|
504 | IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));
|
---|
505 | Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
|
---|
506 | Idtr->Base = (UINTN)IdtGate;
|
---|
507 | Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
|
---|
508 | AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
|
---|
509 |
|
---|
510 | Status = SaveLockBox (
|
---|
511 | &mAcpiS3IdtrProfileGuid,
|
---|
512 | (VOID *)(UINTN)Idtr,
|
---|
513 | (UINTN)sizeof(IA32_DESCRIPTOR)
|
---|
514 | );
|
---|
515 | ASSERT_EFI_ERROR (Status);
|
---|
516 |
|
---|
517 | Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
|
---|
518 | ASSERT_EFI_ERROR (Status);
|
---|
519 |
|
---|
520 | //
|
---|
521 | // Allocate page table
|
---|
522 | //
|
---|
523 | AcpiS3Context->S3NvsPageTableAddress = S3CreateIdentityMappingPageTables ();
|
---|
524 |
|
---|
525 | //
|
---|
526 | // Allocate stack
|
---|
527 | //
|
---|
528 | AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
|
---|
529 | AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
|
---|
530 | ASSERT (AcpiS3Context->BootScriptStackBase != 0);
|
---|
531 |
|
---|
532 | //
|
---|
533 | // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
|
---|
534 | //
|
---|
535 | AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
|
---|
536 | SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
|
---|
537 |
|
---|
538 | DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));
|
---|
539 | DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));
|
---|
540 | DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));
|
---|
541 | DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));
|
---|
542 |
|
---|
543 | Status = SaveLockBox (
|
---|
544 | &gEfiAcpiVariableGuid,
|
---|
545 | &AcpiS3ContextBuffer,
|
---|
546 | sizeof(AcpiS3ContextBuffer)
|
---|
547 | );
|
---|
548 | ASSERT_EFI_ERROR (Status);
|
---|
549 |
|
---|
550 | Status = SaveLockBox (
|
---|
551 | &gEfiAcpiS3ContextGuid,
|
---|
552 | (VOID *)(UINTN)AcpiS3Context,
|
---|
553 | (UINTN)sizeof(*AcpiS3Context)
|
---|
554 | );
|
---|
555 | ASSERT_EFI_ERROR (Status);
|
---|
556 |
|
---|
557 | Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
|
---|
558 | ASSERT_EFI_ERROR (Status);
|
---|
559 |
|
---|
560 | //
|
---|
561 | // Save the boot script too. Note that this requires/includes emitting the
|
---|
562 | // DxeSmmReadyToLock event, which in turn locks down SMM.
|
---|
563 | //
|
---|
564 | SaveS3BootScript ();
|
---|
565 | return EFI_SUCCESS;
|
---|
566 | }
|
---|
567 |
|
---|
568 | /**
|
---|
569 | The Driver Entry Point.
|
---|
570 |
|
---|
571 | The function is the driver Entry point which will produce AcpiS3SaveProtocol.
|
---|
572 |
|
---|
573 | @param ImageHandle A handle for the image that is initializing this driver
|
---|
574 | @param SystemTable A pointer to the EFI system table
|
---|
575 |
|
---|
576 | @retval EFI_SUCCESS: Driver initialized successfully
|
---|
577 | @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
|
---|
578 | @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
|
---|
579 |
|
---|
580 | **/
|
---|
581 | EFI_STATUS
|
---|
582 | EFIAPI
|
---|
583 | InstallAcpiS3Save (
|
---|
584 | IN EFI_HANDLE ImageHandle,
|
---|
585 | IN EFI_SYSTEM_TABLE *SystemTable
|
---|
586 | )
|
---|
587 | {
|
---|
588 | EFI_STATUS Status;
|
---|
589 |
|
---|
590 | if (!QemuFwCfgS3Enabled()) {
|
---|
591 | return EFI_LOAD_ERROR;
|
---|
592 | }
|
---|
593 |
|
---|
594 | if (!FeaturePcdGet(PcdPlatformCsmSupport)) {
|
---|
595 | //
|
---|
596 | // More memory for no CSM tip, because GDT need relocation
|
---|
597 | //
|
---|
598 | mLegacyRegionSize = 0x250;
|
---|
599 | } else {
|
---|
600 | mLegacyRegionSize = 0x100;
|
---|
601 | }
|
---|
602 |
|
---|
603 | Status = gBS->InstallMultipleProtocolInterfaces (
|
---|
604 | &ImageHandle,
|
---|
605 | &gEfiAcpiS3SaveProtocolGuid, &mS3Save,
|
---|
606 | &gEfiLockBoxProtocolGuid, NULL,
|
---|
607 | NULL
|
---|
608 | );
|
---|
609 | ASSERT_EFI_ERROR (Status);
|
---|
610 | return Status;
|
---|
611 | }
|
---|