]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Acpi/S3SaveStateDxe/AcpiS3ContextSave.c
IntelSiliconPkg IntelVTdDxe: Use new EfiLocateFirstAcpiTable()
[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
d1102dba 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
bd890a73
SZ
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions\r
8of the BSD License which accompanies this distribution. The\r
9full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include <PiDxe.h>\r
18#include <Library/BaseLib.h>\r
19#include <Library/BaseMemoryLib.h>\r
20#include <Library/UefiBootServicesTableLib.h>\r
21#include <Library/HobLib.h>\r
22#include <Library/LockBoxLib.h>\r
23#include <Library/PcdLib.h>\r
24#include <Library/DebugLib.h>\r
25#include <Guid/AcpiS3Context.h>\r
26#include <Guid/Acpi.h>\r
27#include <IndustryStandard/Acpi.h>\r
28#include <Protocol/LockBox.h>\r
29\r
30//\r
31// 8 extra pages for PF handler.\r
32//\r
33#define EXTRA_PAGE_TABLE_PAGES 8\r
34\r
35EFI_GUID mAcpiS3IdtrProfileGuid = {\r
36 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }\r
37};\r
38\r
39/**\r
40 Allocate memory below 4G memory address.\r
41\r
42 This function allocates memory below 4G memory address.\r
43\r
44 @param MemoryType Memory type of memory to allocate.\r
45 @param Size Size of memory to allocate.\r
d1102dba 46\r
bd890a73
SZ
47 @return Allocated address for output.\r
48\r
49**/\r
50VOID*\r
51AllocateMemoryBelow4G (\r
52 IN EFI_MEMORY_TYPE MemoryType,\r
53 IN UINTN Size\r
54 )\r
55{\r
56 UINTN Pages;\r
57 EFI_PHYSICAL_ADDRESS Address;\r
58 EFI_STATUS Status;\r
59 VOID* Buffer;\r
60\r
61 Pages = EFI_SIZE_TO_PAGES (Size);\r
62 Address = 0xffffffff;\r
63\r
64 Status = gBS->AllocatePages (\r
65 AllocateMaxAddress,\r
66 MemoryType,\r
67 Pages,\r
68 &Address\r
69 );\r
70 ASSERT_EFI_ERROR (Status);\r
71\r
72 Buffer = (VOID *) (UINTN) Address;\r
73 ZeroMem (Buffer, Size);\r
74\r
75 return Buffer;\r
76}\r
77\r
78/**\r
79\r
80 This function scan ACPI table in RSDT.\r
81\r
82 @param Rsdt ACPI RSDT\r
83 @param Signature ACPI table signature\r
84\r
85 @return ACPI table\r
86\r
87**/\r
88VOID *\r
89ScanTableInRSDT (\r
90 IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,\r
91 IN UINT32 Signature\r
92 )\r
93{\r
94 UINTN Index;\r
95 UINT32 EntryCount;\r
96 UINT32 *EntryPtr;\r
97 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
98\r
99 if (Rsdt == NULL) {\r
100 return NULL;\r
101 }\r
102\r
103 EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);\r
d1102dba 104\r
bd890a73
SZ
105 EntryPtr = (UINT32 *)(Rsdt + 1);\r
106 for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {\r
107 Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));\r
108 if (Table->Signature == Signature) {\r
109 return Table;\r
110 }\r
111 }\r
d1102dba 112\r
bd890a73
SZ
113 return NULL;\r
114}\r
115\r
116/**\r
117\r
118 This function scan ACPI table in XSDT.\r
119\r
120 @param Xsdt ACPI XSDT\r
121 @param Signature ACPI table signature\r
122\r
123 @return ACPI table\r
124\r
125**/\r
126VOID *\r
127ScanTableInXSDT (\r
128 IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,\r
129 IN UINT32 Signature\r
130 )\r
131{\r
132 UINTN Index;\r
133 UINT32 EntryCount;\r
134 UINT64 EntryPtr;\r
135 UINTN BasePtr;\r
136 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
137\r
138 if (Xsdt == NULL) {\r
139 return NULL;\r
140 }\r
141\r
142 EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);\r
d1102dba 143\r
bd890a73
SZ
144 BasePtr = (UINTN)(Xsdt + 1);\r
145 for (Index = 0; Index < EntryCount; Index ++) {\r
146 CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));\r
147 Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));\r
148 if (Table->Signature == Signature) {\r
149 return Table;\r
150 }\r
151 }\r
d1102dba 152\r
bd890a73
SZ
153 return NULL;\r
154}\r
155\r
156/**\r
157 To find Facs in FADT.\r
158\r
159 @param Fadt FADT table pointer\r
d1102dba 160\r
bd890a73
SZ
161 @return Facs table pointer.\r
162**/\r
163EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *\r
164FindAcpiFacsFromFadt (\r
165 IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt\r
166 )\r
167{\r
168 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
169 UINT64 Data64;\r
170\r
171 if (Fadt == NULL) {\r
172 return NULL;\r
173 }\r
174\r
175 if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {\r
176 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;\r
177 } else {\r
178 if (Fadt->FirmwareCtrl != 0) {\r
179 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;\r
180 } else {\r
181 CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));\r
182 Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;\r
183 }\r
184 }\r
185 return Facs;\r
186}\r
187\r
188/**\r
189 To find Facs in Acpi tables.\r
d1102dba
LG
190\r
191 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored\r
bd890a73
SZ
192 in the table.\r
193\r
194 @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.\r
d1102dba 195\r
bd890a73
SZ
196 @return Facs table pointer.\r
197**/\r
198EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *\r
199FindAcpiFacsTableByAcpiGuid (\r
200 IN EFI_GUID *AcpiTableGuid\r
201 )\r
202{\r
203 EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;\r
204 EFI_ACPI_DESCRIPTION_HEADER *Rsdt;\r
205 EFI_ACPI_DESCRIPTION_HEADER *Xsdt;\r
206 EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;\r
207 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
208 UINTN Index;\r
209\r
210 Rsdp = NULL;\r
211 //\r
212 // found ACPI table RSD_PTR from system table\r
213 //\r
214 for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
215 if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {\r
216 //\r
217 // A match was found.\r
218 //\r
219 Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
220 break;\r
221 }\r
222 }\r
223\r
224 if (Rsdp == NULL) {\r
225 return NULL;\r
226 }\r
227\r
228 //\r
229 // Search XSDT\r
230 //\r
231 if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {\r
232 Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;\r
233 Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);\r
234 if (Fadt != NULL) {\r
235 Facs = FindAcpiFacsFromFadt (Fadt);\r
236 if (Facs != NULL) {\r
237 return Facs;\r
238 }\r
239 }\r
240 }\r
241\r
242 //\r
243 // Search RSDT\r
244 //\r
245 Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;\r
246 Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);\r
247 if (Fadt != NULL) {\r
248 Facs = FindAcpiFacsFromFadt (Fadt);\r
249 if (Facs != NULL) {\r
250 return Facs;\r
251 }\r
252 }\r
253\r
254 return NULL;\r
255}\r
256\r
257/**\r
258 To find Facs in Acpi tables.\r
d1102dba
LG
259\r
260 To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored\r
bd890a73 261 in the table.\r
d1102dba 262\r
bd890a73
SZ
263 @return Facs table pointer.\r
264**/\r
265EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *\r
266FindAcpiFacsTable (\r
267 VOID\r
268 )\r
269{\r
270 EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
271\r
272 Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);\r
273 if (Facs != NULL) {\r
274 return Facs;\r
275 }\r
276\r
277 return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);\r
278}\r
279\r
280/**\r
281 The function will check if long mode waking vector is supported.\r
282\r
283 @param[in] Facs Pointer to FACS table.\r
284\r
285 @retval TRUE Long mode waking vector is supported.\r
286 @retval FALSE Long mode waking vector is not supported.\r
287\r
288**/\r
289BOOLEAN\r
290IsLongModeWakingVectorSupport (\r
291 IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs\r
292 )\r
293{\r
294 if ((Facs == NULL) ||\r
295 (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ) {\r
296 //\r
297 // Something wrong with FACS.\r
298 //\r
299 return FALSE;\r
300 }\r
301 if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
302 ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0)) {\r
303 //\r
304 // BIOS supports 64bit waking vector.\r
305 //\r
306 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
307 return TRUE;\r
308 }\r
309 }\r
310 return FALSE;\r
311}\r
312\r
313/**\r
314 Allocates page table buffer.\r
315\r
316 @param[in] LongModeWakingVectorSupport Support long mode waking vector or not.\r
317\r
d1102dba 318 If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1\r
bd890a73
SZ
319 virtual to physical mapping page table when long mode waking vector is supported, otherwise\r
320 create 4G page table when long mode waking vector is not supported and let PF handler to\r
321 handle > 4G request.\r
d1102dba
LG
322 If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.\r
323\r
324 @return Page table base address.\r
bd890a73
SZ
325\r
326**/\r
327EFI_PHYSICAL_ADDRESS\r
328S3AllocatePageTablesBuffer (\r
329 IN BOOLEAN LongModeWakingVectorSupport\r
330 )\r
d1102dba 331{\r
bd890a73
SZ
332 if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {\r
333 UINTN ExtraPageTablePages;\r
334 UINT32 RegEax;\r
335 UINT32 RegEdx;\r
336 UINT8 PhysicalAddressBits;\r
337 UINT32 NumberOfPml4EntriesNeeded;\r
338 UINT32 NumberOfPdpEntriesNeeded;\r
339 EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;\r
340 UINTN TotalPageTableSize;\r
341 VOID *Hob;\r
342 BOOLEAN Page1GSupport;\r
343\r
344 Page1GSupport = FALSE;\r
345 if (PcdGetBool(PcdUse1GPageTable)) {\r
346 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
347 if (RegEax >= 0x80000001) {\r
348 AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);\r
349 if ((RegEdx & BIT26) != 0) {\r
350 Page1GSupport = TRUE;\r
351 }\r
352 }\r
353 }\r
354\r
355 //\r
356 // Get physical address bits supported.\r
357 //\r
358 Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
359 if (Hob != NULL) {\r
360 PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
361 } else {\r
362 AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
363 if (RegEax >= 0x80000008) {\r
364 AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
365 PhysicalAddressBits = (UINT8) RegEax;\r
366 } else {\r
367 PhysicalAddressBits = 36;\r
368 }\r
369 }\r
370\r
371 //\r
372 // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.\r
373 //\r
374 ASSERT (PhysicalAddressBits <= 52);\r
375 if (PhysicalAddressBits > 48) {\r
376 PhysicalAddressBits = 48;\r
377 }\r
378\r
379 ExtraPageTablePages = 0;\r
380 if (!LongModeWakingVectorSupport) {\r
381 //\r
382 // Create 4G page table when BIOS does not support long mode waking vector,\r
383 // and let PF handler to handle > 4G request.\r
384 //\r
385 PhysicalAddressBits = 32;\r
386 ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;\r
387 }\r
388\r
389 //\r
390 // Calculate the table entries needed.\r
391 //\r
392 if (PhysicalAddressBits <= 39 ) {\r
393 NumberOfPml4EntriesNeeded = 1;\r
394 NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));\r
395 } else {\r
396 NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));\r
397 NumberOfPdpEntriesNeeded = 512;\r
398 }\r
399\r
400 //\r
401 // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.\r
402 //\r
403 if (!Page1GSupport) {\r
16f69227 404 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded;\r
bd890a73 405 } else {\r
16f69227 406 TotalPageTableSize = 1 + NumberOfPml4EntriesNeeded;\r
bd890a73
SZ
407 }\r
408\r
409 TotalPageTableSize += ExtraPageTablePages;\r
558f58e3 410 DEBUG ((DEBUG_INFO, "AcpiS3ContextSave TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));\r
bd890a73
SZ
411\r
412 //\r
413 // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.\r
414 //\r
415 S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));\r
416 ASSERT (S3NvsPageTableAddress != 0);\r
417 return S3NvsPageTableAddress;\r
418 } else {\r
419 //\r
420 // If DXE is running 32-bit mode, no need to establish page table.\r
421 //\r
d1102dba 422 return (EFI_PHYSICAL_ADDRESS) 0;\r
bd890a73
SZ
423 }\r
424}\r
425\r
426/**\r
427 Callback function executed when the EndOfDxe event group is signaled.\r
428\r
429 @param[in] Event Event whose notification function is being invoked.\r
430 @param[in] Context The pointer to the notification function's context, which\r
431 is implementation-dependent.\r
432**/\r
433VOID\r
434EFIAPI\r
435AcpiS3ContextSaveOnEndOfDxe (\r
436 IN EFI_EVENT Event,\r
437 IN VOID *Context\r
438 )\r
439{\r
440 EFI_STATUS Status;\r
441 EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;\r
442 ACPI_S3_CONTEXT *AcpiS3Context;\r
443 IA32_DESCRIPTOR *Idtr;\r
444 IA32_IDT_GATE_DESCRIPTOR *IdtGate;\r
445 EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;\r
446 VOID *Interface;\r
447\r
448 DEBUG ((EFI_D_INFO, "AcpiS3ContextSave!\n"));\r
449\r
450 Status = gBS->LocateProtocol (&gEfiLockBoxProtocolGuid, NULL, &Interface);\r
451 if (EFI_ERROR (Status)) {\r
452 DEBUG ((EFI_D_INFO | EFI_D_WARN, "ACPI S3 context can't be saved without LockBox!\n"));\r
453 goto Done;\r
454 }\r
455\r
456 AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));\r
457 ASSERT (AcpiS3Context != NULL);\r
458 AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;\r
459\r
460 //\r
461 // Get ACPI Table because we will save its position to variable\r
462 //\r
463 Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) FindAcpiFacsTable ();\r
464 AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS) (UINTN) Facs;\r
465 ASSERT (AcpiS3Context->AcpiFacsTable != 0);\r
466\r
467 IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));\r
468 Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);\r
469 Idtr->Base = (UINTN)IdtGate;\r
470 Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);\r
471 AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;\r
472\r
473 Status = SaveLockBox (\r
474 &mAcpiS3IdtrProfileGuid,\r
475 (VOID *)(UINTN)Idtr,\r
476 (UINTN)sizeof(IA32_DESCRIPTOR)\r
477 );\r
478 ASSERT_EFI_ERROR (Status);\r
479\r
480 Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
481 ASSERT_EFI_ERROR (Status);\r
482\r
483 //\r
484 // Allocate page table\r
485 //\r
486 AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));\r
487\r
488 //\r
489 // Allocate stack\r
490 //\r
491 AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);\r
492 AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));\r
493 ASSERT (AcpiS3Context->BootScriptStackBase != 0);\r
494\r
495 //\r
496 // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.\r
497 //\r
498 AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);\r
499 SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);\r
500\r
501 DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));\r
502 DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));\r
503 DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));\r
504 DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));\r
505 DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));\r
506 DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));\r
507\r
508 Status = SaveLockBox (\r
509 &gEfiAcpiVariableGuid,\r
510 &AcpiS3ContextBuffer,\r
511 sizeof(AcpiS3ContextBuffer)\r
512 );\r
513 ASSERT_EFI_ERROR (Status);\r
514\r
515 Status = SaveLockBox (\r
516 &gEfiAcpiS3ContextGuid,\r
517 (VOID *)(UINTN)AcpiS3Context,\r
518 (UINTN)sizeof(*AcpiS3Context)\r
519 );\r
520 ASSERT_EFI_ERROR (Status);\r
521\r
522 Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);\r
523 ASSERT_EFI_ERROR (Status);\r
524\r
525Done:\r
526 //\r
527 // Close the event, deregistering the callback and freeing resources.\r
528 //\r
529 Status = gBS->CloseEvent (Event);\r
530 ASSERT_EFI_ERROR (Status);\r
531}\r
532\r