1 /** @file
2   This is an implementation of the AcpiVariable platform field for ECP platform.
3 
4 Copyright (c) 2006 - 2014, 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 #include <Guid/AcpiS3Context.h>
47 
48 GLOBAL_REMOVE_IF_UNREFERENCED
49 ACPI_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 **/
62 VOID*
63 AllocateMemoryBelow4G (
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 **/
73 VOID
S3ReadyThunkPlatform(IN ACPI_S3_CONTEXT * AcpiS3Context)74 S3ReadyThunkPlatform (
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 **/
133 VOID
134 EFIAPI
VariableLockAcpiGlobalVariable(IN EFI_EVENT Event,IN VOID * Context)135 VariableLockAcpiGlobalVariable (
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 **/
155 VOID
InstallAcpiS3SaveThunk(VOID)156 InstallAcpiS3SaveThunk (
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