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