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