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
S3ReadyThunkPlatform(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
VariableLockAcpiGlobalVariable(IN EFI_EVENT Event,IN VOID * Context)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
InstallAcpiS3SaveThunk(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