| /** @file | |
| This is an implementation of the AcpiVariable platform field for ECP platform. | |
| Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions | |
| of the BSD License which accompanies this distribution. The | |
| full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| == | |
| typedef struct { | |
| EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase; <<=== | |
| UINT32 AcpiReservedMemorySize; <<=== | |
| EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase; | |
| EFI_PHYSICAL_ADDRESS AcpiBootScriptTable; | |
| EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase; | |
| EFI_PHYSICAL_ADDRESS AcpiFacsTable; | |
| UINT64 SystemMemoryLength; <<=== | |
| ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData; | |
| EFI_PHYSICAL_ADDRESS VideoOpromAddress; | |
| UINT32 VideoOpromSize; | |
| EFI_PHYSICAL_ADDRESS S3DebugBufferAddress; | |
| EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint; | |
| } ACPI_VARIABLE_SET_COMPATIBILITY; | |
| **/ | |
| #include <FrameworkDxe.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/UefiBootServicesTableLib.h> | |
| #include <Library/UefiRuntimeServicesTableLib.h> | |
| #include <Library/HobLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Protocol/FrameworkMpService.h> | |
| #include <Protocol/VariableLock.h> | |
| #include <Guid/AcpiVariableCompatibility.h> | |
| GLOBAL_REMOVE_IF_UNREFERENCED | |
| ACPI_VARIABLE_SET_COMPATIBILITY *mAcpiVariableSetCompatibility = NULL; | |
| /** | |
| Allocate memory below 4G memory address. | |
| This function allocates memory below 4G memory address. | |
| @param MemoryType Memory type of memory to allocate. | |
| @param Size Size of memory to allocate. | |
| @return Allocated address for output. | |
| **/ | |
| VOID* | |
| AllocateMemoryBelow4G ( | |
| IN EFI_MEMORY_TYPE MemoryType, | |
| IN UINTN Size | |
| ); | |
| /** | |
| Hook point for AcpiVariableThunkPlatform for S3Ready. | |
| **/ | |
| VOID | |
| S3ReadyThunkPlatform ( | |
| VOID | |
| ) | |
| { | |
| EFI_PHYSICAL_ADDRESS AcpiMemoryBase; | |
| UINT32 AcpiMemorySize; | |
| EFI_PEI_HOB_POINTERS Hob; | |
| UINT64 MemoryLength; | |
| DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n")); | |
| if (mAcpiVariableSetCompatibility == NULL) { | |
| return; | |
| } | |
| // | |
| // Allocate ACPI reserved memory under 4G | |
| // | |
| AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize)); | |
| ASSERT (AcpiMemoryBase != 0); | |
| AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); | |
| // | |
| // Calculate the system memory length by memory hobs | |
| // | |
| MemoryLength = 0x100000; | |
| Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); | |
| ASSERT (Hob.Raw != NULL); | |
| while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { | |
| if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { | |
| // | |
| // Skip the memory region below 1MB | |
| // | |
| if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { | |
| MemoryLength += Hob.ResourceDescriptor->ResourceLength; | |
| } | |
| } | |
| Hob.Raw = GET_NEXT_HOB (Hob); | |
| Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); | |
| } | |
| mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase; | |
| mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize; | |
| mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength; | |
| DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase)); | |
| DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize)); | |
| DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength)); | |
| return ; | |
| } | |
| /** | |
| Register callback function upon VariableLockProtocol | |
| to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. | |
| @param[in] Event Event whose notification function is being invoked. | |
| @param[in] Context Pointer to the notification function's context. | |
| **/ | |
| VOID | |
| EFIAPI | |
| VariableLockAcpiGlobalVariable ( | |
| IN EFI_EVENT Event, | |
| IN VOID *Context | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; | |
| // | |
| // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists | |
| // | |
| Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); | |
| if (!EFI_ERROR (Status)) { | |
| Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid); | |
| ASSERT_EFI_ERROR (Status); | |
| } | |
| } | |
| /** | |
| Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. | |
| **/ | |
| VOID | |
| InstallAcpiS3SaveThunk ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService; | |
| UINTN VarSize; | |
| VOID *Registration; | |
| Status = gBS->LocateProtocol ( | |
| &gFrameworkEfiMpServiceProtocolGuid, | |
| NULL, | |
| (VOID**) &FrameworkMpService | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set | |
| // should be produced by CPU driver. | |
| // | |
| VarSize = sizeof (mAcpiVariableSetCompatibility); | |
| Status = gRT->GetVariable ( | |
| ACPI_GLOBAL_VARIABLE, | |
| &gEfiAcpiVariableCompatiblityGuid, | |
| NULL, | |
| &VarSize, | |
| &mAcpiVariableSetCompatibility | |
| ); | |
| if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) { | |
| DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n")); | |
| mAcpiVariableSetCompatibility = NULL; | |
| } | |
| } else { | |
| // | |
| // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform | |
| // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase, | |
| // so RT attribute is not needed for it. | |
| // | |
| mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY)); | |
| Status = gRT->SetVariable ( | |
| ACPI_GLOBAL_VARIABLE, | |
| &gEfiAcpiVariableCompatiblityGuid, | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, | |
| sizeof(mAcpiVariableSetCompatibility), | |
| &mAcpiVariableSetCompatibility | |
| ); | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Register callback function upon VariableLockProtocol | |
| // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. | |
| // | |
| EfiCreateProtocolNotifyEvent ( | |
| &gEdkiiVariableLockProtocolGuid, | |
| TPL_CALLBACK, | |
| VariableLockAcpiGlobalVariable, | |
| NULL, | |
| &Registration | |
| ); | |
| } else { | |
| DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status)); | |
| gBS->FreePages ( | |
| (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility, | |
| EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY)) | |
| ); | |
| mAcpiVariableSetCompatibility = NULL; | |
| } | |
| } | |
| DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility)); | |
| } |