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