1/** @file 2 This is an implementation of the AcpiVariable platform field for ECP platform. 3 4Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR> 5 6This program and the accompanying materials 7are licensed and made available under the terms and conditions 8of the BSD License which accompanies this distribution. The 9full text of the license may be found at 10http://opensource.org/licenses/bsd-license.php 11 12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 14 15== 16 17typedef struct { 18 EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase; <<=== 19 UINT32 AcpiReservedMemorySize; <<=== 20 EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase; 21 EFI_PHYSICAL_ADDRESS AcpiBootScriptTable; 22 EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase; 23 EFI_PHYSICAL_ADDRESS AcpiFacsTable; 24 UINT64 SystemMemoryLength; <<=== 25 ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData; 26 EFI_PHYSICAL_ADDRESS VideoOpromAddress; 27 UINT32 VideoOpromSize; 28 EFI_PHYSICAL_ADDRESS S3DebugBufferAddress; 29 EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint; 30} ACPI_VARIABLE_SET_COMPATIBILITY; 31 32**/ 33 34#include <FrameworkDxe.h> 35#include <Library/BaseLib.h> 36#include <Library/BaseMemoryLib.h> 37#include <Library/UefiBootServicesTableLib.h> 38#include <Library/UefiRuntimeServicesTableLib.h> 39#include <Library/HobLib.h> 40#include <Library/PcdLib.h> 41#include <Library/DebugLib.h> 42#include <Library/UefiLib.h> 43#include <Protocol/FrameworkMpService.h> 44#include <Protocol/VariableLock.h> 45#include <Guid/AcpiVariableCompatibility.h> 46#include <Guid/AcpiS3Context.h> 47 48GLOBAL_REMOVE_IF_UNREFERENCED 49ACPI_VARIABLE_SET_COMPATIBILITY *mAcpiVariableSetCompatibility = NULL; 50 51/** 52 Allocate memory below 4G memory address. 53 54 This function allocates memory below 4G memory address. 55 56 @param MemoryType Memory type of memory to allocate. 57 @param Size Size of memory to allocate. 58 59 @return Allocated address for output. 60 61**/ 62VOID* 63AllocateMemoryBelow4G ( 64 IN EFI_MEMORY_TYPE MemoryType, 65 IN UINTN Size 66 ); 67 68/** 69 Hook point for AcpiVariableThunkPlatform for S3Ready. 70 71 @param AcpiS3Context ACPI s3 context 72**/ 73VOID 74S3ReadyThunkPlatform ( 75 IN ACPI_S3_CONTEXT *AcpiS3Context 76 ) 77{ 78 EFI_PHYSICAL_ADDRESS AcpiMemoryBase; 79 UINT32 AcpiMemorySize; 80 EFI_PEI_HOB_POINTERS Hob; 81 UINT64 MemoryLength; 82 83 DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n")); 84 85 if (mAcpiVariableSetCompatibility == NULL) { 86 return; 87 } 88 89 // 90 // Allocate ACPI reserved memory under 4G 91 // 92 AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize)); 93 ASSERT (AcpiMemoryBase != 0); 94 AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize); 95 96 // 97 // Calculate the system memory length by memory hobs 98 // 99 MemoryLength = 0x100000; 100 Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR); 101 ASSERT (Hob.Raw != NULL); 102 while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) { 103 if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) { 104 // 105 // Skip the memory region below 1MB 106 // 107 if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) { 108 MemoryLength += Hob.ResourceDescriptor->ResourceLength; 109 } 110 } 111 Hob.Raw = GET_NEXT_HOB (Hob); 112 Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw); 113 } 114 115 mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase; 116 mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize; 117 mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength; 118 119 DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase)); 120 DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize)); 121 DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength)); 122 123 return ; 124} 125 126/** 127 Register callback function upon VariableLockProtocol 128 to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. 129 130 @param[in] Event Event whose notification function is being invoked. 131 @param[in] Context Pointer to the notification function's context. 132**/ 133VOID 134EFIAPI 135VariableLockAcpiGlobalVariable ( 136 IN EFI_EVENT Event, 137 IN VOID *Context 138 ) 139{ 140 EFI_STATUS Status; 141 EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock; 142 // 143 // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists 144 // 145 Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock); 146 if (!EFI_ERROR (Status)) { 147 Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid); 148 ASSERT_EFI_ERROR (Status); 149 } 150} 151 152/** 153 Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save. 154**/ 155VOID 156InstallAcpiS3SaveThunk ( 157 VOID 158 ) 159{ 160 EFI_STATUS Status; 161 FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService; 162 UINTN VarSize; 163 VOID *Registration; 164 165 Status = gBS->LocateProtocol ( 166 &gFrameworkEfiMpServiceProtocolGuid, 167 NULL, 168 (VOID**) &FrameworkMpService 169 ); 170 if (!EFI_ERROR (Status)) { 171 // 172 // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set 173 // should be produced by CPU driver. 174 // 175 VarSize = sizeof (mAcpiVariableSetCompatibility); 176 Status = gRT->GetVariable ( 177 ACPI_GLOBAL_VARIABLE, 178 &gEfiAcpiVariableCompatiblityGuid, 179 NULL, 180 &VarSize, 181 &mAcpiVariableSetCompatibility 182 ); 183 if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) { 184 DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n")); 185 mAcpiVariableSetCompatibility = NULL; 186 } 187 } else { 188 // 189 // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform 190 // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase, 191 // so RT attribute is not needed for it. 192 // 193 mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY)); 194 Status = gRT->SetVariable ( 195 ACPI_GLOBAL_VARIABLE, 196 &gEfiAcpiVariableCompatiblityGuid, 197 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE, 198 sizeof(mAcpiVariableSetCompatibility), 199 &mAcpiVariableSetCompatibility 200 ); 201 if (!EFI_ERROR (Status)) { 202 // 203 // Register callback function upon VariableLockProtocol 204 // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it. 205 // 206 EfiCreateProtocolNotifyEvent ( 207 &gEdkiiVariableLockProtocolGuid, 208 TPL_CALLBACK, 209 VariableLockAcpiGlobalVariable, 210 NULL, 211 &Registration 212 ); 213 } else { 214 DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status)); 215 gBS->FreePages ( 216 (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility, 217 EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY)) 218 ); 219 mAcpiVariableSetCompatibility = NULL; 220 } 221 } 222 223 DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility)); 224} 225