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