]>
Commit | Line | Data |
---|---|---|
6b0d7b01 MK |
1 | /** @file\r |
2 | Common variable non-volatile store routines.\r | |
3 | \r | |
4 | Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r | |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | \r | |
7 | **/\r | |
8 | \r | |
9 | #include "VariableNonVolatile.h"\r | |
10 | #include "VariableParsing.h"\r | |
11 | \r | |
12 | extern VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r | |
13 | \r | |
14 | /**\r | |
15 | Get non-volatile maximum variable size.\r | |
16 | \r | |
17 | @return Non-volatile maximum variable size.\r | |
18 | \r | |
19 | **/\r | |
20 | UINTN\r | |
21 | GetNonVolatileMaxVariableSize (\r | |
22 | VOID\r | |
23 | )\r | |
24 | {\r | |
25 | if (PcdGet32 (PcdHwErrStorageSize) != 0) {\r | |
26 | return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),\r | |
27 | PcdGet32 (PcdMaxHardwareErrorVariableSize));\r | |
28 | } else {\r | |
29 | return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));\r | |
30 | }\r | |
31 | }\r | |
32 | \r | |
33 | /**\r | |
34 | Init emulated non-volatile variable store.\r | |
35 | \r | |
36 | @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.\r | |
37 | \r | |
38 | @retval EFI_SUCCESS Function successfully executed.\r | |
39 | @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r | |
40 | \r | |
41 | **/\r | |
42 | EFI_STATUS\r | |
43 | InitEmuNonVolatileVariableStore (\r | |
44 | OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase\r | |
45 | )\r | |
46 | {\r | |
47 | VARIABLE_STORE_HEADER *VariableStore;\r | |
48 | UINT32 VariableStoreLength;\r | |
49 | BOOLEAN FullyInitializeStore;\r | |
50 | UINT32 HwErrStorageSize;\r | |
51 | \r | |
52 | FullyInitializeStore = TRUE;\r | |
53 | \r | |
54 | VariableStoreLength = PcdGet32 (PcdVariableStoreSize);\r | |
55 | ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r | |
56 | \r | |
57 | //\r | |
58 | // Allocate memory for variable store.\r | |
59 | //\r | |
60 | if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {\r | |
61 | VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);\r | |
62 | if (VariableStore == NULL) {\r | |
63 | return EFI_OUT_OF_RESOURCES;\r | |
64 | }\r | |
65 | } else {\r | |
66 | //\r | |
67 | // A memory location has been reserved for the NV variable store. Certain\r | |
68 | // platforms may be able to preserve a memory range across system resets,\r | |
69 | // thereby providing better NV variable emulation.\r | |
70 | //\r | |
71 | VariableStore =\r | |
72 | (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)\r | |
73 | PcdGet64 (PcdEmuVariableNvStoreReserved);\r | |
74 | if ((VariableStore->Size == VariableStoreLength) &&\r | |
75 | (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||\r | |
76 | CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&\r | |
77 | (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&\r | |
78 | (VariableStore->State == VARIABLE_STORE_HEALTHY)) {\r | |
79 | DEBUG((\r | |
80 | DEBUG_INFO,\r | |
81 | "Variable Store reserved at %p appears to be valid\n",\r | |
82 | VariableStore\r | |
83 | ));\r | |
84 | FullyInitializeStore = FALSE;\r | |
85 | }\r | |
86 | }\r | |
87 | \r | |
88 | if (FullyInitializeStore) {\r | |
89 | SetMem (VariableStore, VariableStoreLength, 0xff);\r | |
90 | //\r | |
91 | // Use gEfiAuthenticatedVariableGuid for potential auth variable support.\r | |
92 | //\r | |
93 | CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r | |
94 | VariableStore->Size = VariableStoreLength;\r | |
95 | VariableStore->Format = VARIABLE_STORE_FORMATTED;\r | |
96 | VariableStore->State = VARIABLE_STORE_HEALTHY;\r | |
97 | VariableStore->Reserved = 0;\r | |
98 | VariableStore->Reserved1 = 0;\r | |
99 | }\r | |
100 | \r | |
101 | *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r | |
102 | \r | |
103 | HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r | |
104 | \r | |
105 | //\r | |
106 | // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r | |
107 | // is stored with common variable in the same NV region. So the platform integrator should\r | |
108 | // ensure that the value of PcdHwErrStorageSize is less than the value of\r | |
109 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r | |
110 | //\r | |
111 | ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r | |
112 | \r | |
113 | mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r | |
114 | mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r | |
115 | mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;\r | |
116 | \r | |
117 | return EFI_SUCCESS;\r | |
118 | }\r | |
119 | \r | |
120 | /**\r | |
121 | Init real non-volatile variable store.\r | |
122 | \r | |
123 | @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.\r | |
124 | \r | |
125 | @retval EFI_SUCCESS Function successfully executed.\r | |
126 | @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r | |
127 | @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r | |
128 | \r | |
129 | **/\r | |
130 | EFI_STATUS\r | |
131 | InitRealNonVolatileVariableStore (\r | |
132 | OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase\r | |
133 | )\r | |
134 | {\r | |
135 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r | |
136 | VARIABLE_STORE_HEADER *VariableStore;\r | |
137 | UINT32 VariableStoreLength;\r | |
138 | EFI_HOB_GUID_TYPE *GuidHob;\r | |
139 | EFI_PHYSICAL_ADDRESS NvStorageBase;\r | |
140 | UINT8 *NvStorageData;\r | |
141 | UINT32 NvStorageSize;\r | |
142 | FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r | |
143 | UINT32 BackUpOffset;\r | |
144 | UINT32 BackUpSize;\r | |
145 | UINT32 HwErrStorageSize;\r | |
146 | UINT32 MaxUserNvVariableSpaceSize;\r | |
147 | UINT32 BoottimeReservedNvVariableSpaceSize;\r | |
148 | EFI_STATUS Status;\r | |
149 | VOID *FtwProtocol;\r | |
150 | \r | |
151 | mVariableModuleGlobal->FvbInstance = NULL;\r | |
152 | \r | |
153 | //\r | |
154 | // Allocate runtime memory used for a memory copy of the FLASH region.\r | |
155 | // Keep the memory and the FLASH in sync as updates occur.\r | |
156 | //\r | |
157 | NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r | |
158 | NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r | |
159 | if (NvStorageData == NULL) {\r | |
160 | return EFI_OUT_OF_RESOURCES;\r | |
161 | }\r | |
162 | \r | |
163 | NvStorageBase = NV_STORAGE_VARIABLE_BASE;\r | |
164 | ASSERT (NvStorageBase != 0);\r | |
165 | \r | |
166 | //\r | |
167 | // Copy NV storage data to the memory buffer.\r | |
168 | //\r | |
169 | CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r | |
170 | \r | |
171 | Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r | |
172 | //\r | |
173 | // If FTW protocol has been installed, no need to check FTW last write data hob.\r | |
174 | //\r | |
175 | if (EFI_ERROR (Status)) {\r | |
176 | //\r | |
177 | // Check the FTW last write data hob.\r | |
178 | //\r | |
179 | GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r | |
180 | if (GuidHob != NULL) {\r | |
181 | FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r | |
182 | if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r | |
183 | DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r | |
184 | //\r | |
185 | // Copy the backed up NV storage data to the memory buffer from spare block.\r | |
186 | //\r | |
187 | CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r | |
188 | } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r | |
189 | (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r | |
190 | //\r | |
191 | // Flash NV storage from the Offset is backed up in spare block.\r | |
192 | //\r | |
193 | BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r | |
194 | BackUpSize = NvStorageSize - BackUpOffset;\r | |
195 | DEBUG ((DEBUG_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r | |
196 | //\r | |
197 | // Copy the partial backed up NV storage data to the memory buffer from spare block.\r | |
198 | //\r | |
199 | CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r | |
200 | }\r | |
201 | }\r | |
202 | }\r | |
203 | \r | |
204 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r | |
205 | \r | |
206 | //\r | |
207 | // Check if the Firmware Volume is not corrupted\r | |
208 | //\r | |
209 | if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r | |
210 | FreePool (NvStorageData);\r | |
211 | DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r | |
212 | return EFI_VOLUME_CORRUPTED;\r | |
213 | }\r | |
214 | \r | |
215 | VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);\r | |
216 | VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r | |
217 | ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r | |
218 | ASSERT (VariableStore->Size == VariableStoreLength);\r | |
219 | \r | |
220 | //\r | |
221 | // Check if the Variable Store header is not corrupted\r | |
222 | //\r | |
223 | if (GetVariableStoreStatus (VariableStore) != EfiValid) {\r | |
224 | FreePool (NvStorageData);\r | |
225 | DEBUG((DEBUG_ERROR, "Variable Store header is corrupted\n"));\r | |
226 | return EFI_VOLUME_CORRUPTED;\r | |
227 | }\r | |
228 | \r | |
229 | mNvFvHeaderCache = FvHeader;\r | |
230 | \r | |
231 | *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r | |
232 | \r | |
233 | HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r | |
234 | MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r | |
235 | BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\r | |
236 | \r | |
237 | //\r | |
238 | // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r | |
239 | // is stored with common variable in the same NV region. So the platform integrator should\r | |
240 | // ensure that the value of PcdHwErrStorageSize is less than the value of\r | |
241 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r | |
242 | //\r | |
243 | ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r | |
244 | //\r | |
245 | // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r | |
246 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r | |
247 | //\r | |
248 | ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r | |
249 | //\r | |
250 | // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r | |
251 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r | |
252 | //\r | |
253 | ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r | |
254 | \r | |
255 | mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r | |
256 | mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r | |
257 | mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r | |
258 | \r | |
259 | DEBUG ((\r | |
260 | DEBUG_INFO,\r | |
261 | "Variable driver common space: 0x%x 0x%x 0x%x\n",\r | |
262 | mVariableModuleGlobal->CommonVariableSpace,\r | |
263 | mVariableModuleGlobal->CommonMaxUserVariableSpace,\r | |
264 | mVariableModuleGlobal->CommonRuntimeVariableSpace\r | |
265 | ));\r | |
266 | \r | |
267 | //\r | |
268 | // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r | |
269 | //\r | |
270 | ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r | |
271 | \r | |
272 | return EFI_SUCCESS;\r | |
273 | }\r | |
274 | \r | |
275 | /**\r | |
276 | Init non-volatile variable store.\r | |
277 | \r | |
278 | @retval EFI_SUCCESS Function successfully executed.\r | |
279 | @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r | |
280 | @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r | |
281 | \r | |
282 | **/\r | |
283 | EFI_STATUS\r | |
284 | InitNonVolatileVariableStore (\r | |
285 | VOID\r | |
286 | )\r | |
287 | {\r | |
288 | VARIABLE_HEADER *Variable;\r | |
289 | VARIABLE_HEADER *NextVariable;\r | |
290 | EFI_PHYSICAL_ADDRESS VariableStoreBase;\r | |
291 | UINTN VariableSize;\r | |
292 | EFI_STATUS Status;\r | |
293 | \r | |
294 | if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r | |
295 | Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r | |
296 | if (EFI_ERROR (Status)) {\r | |
297 | return Status;\r | |
298 | }\r | |
299 | mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r | |
300 | DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r | |
301 | } else {\r | |
302 | Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r | |
303 | if (EFI_ERROR (Status)) {\r | |
304 | return Status;\r | |
305 | }\r | |
306 | mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r | |
307 | }\r | |
308 | \r | |
309 | mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r | |
310 | mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r | |
311 | mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r | |
312 | \r | |
313 | mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r | |
314 | mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r | |
315 | \r | |
316 | //\r | |
317 | // Parse non-volatile variable data and get last variable offset.\r | |
318 | //\r | |
319 | Variable = GetStartPointer (mNvVariableCache);\r | |
320 | while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r | |
321 | NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r | |
322 | VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r | |
323 | if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r | |
324 | mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r | |
325 | } else {\r | |
326 | mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r | |
327 | }\r | |
328 | \r | |
329 | Variable = NextVariable;\r | |
330 | }\r | |
331 | mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;\r | |
332 | \r | |
333 | return EFI_SUCCESS;\r | |
334 | }\r |