]>
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 | |
145 | FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r | |
146 | UINT32 BackUpOffset;\r | |
147 | UINT32 BackUpSize;\r | |
148 | UINT32 HwErrStorageSize;\r | |
149 | UINT32 MaxUserNvVariableSpaceSize;\r | |
150 | UINT32 BoottimeReservedNvVariableSpaceSize;\r | |
151 | EFI_STATUS Status;\r | |
152 | VOID *FtwProtocol;\r | |
153 | \r | |
154 | mVariableModuleGlobal->FvbInstance = NULL;\r | |
155 | \r | |
156 | //\r | |
157 | // Allocate runtime memory used for a memory copy of the FLASH region.\r | |
158 | // Keep the memory and the FLASH in sync as updates occur.\r | |
159 | //\r | |
160 | NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r | |
161 | NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r | |
162 | if (NvStorageData == NULL) {\r | |
163 | return EFI_OUT_OF_RESOURCES;\r | |
164 | }\r | |
165 | \r | |
166 | NvStorageBase = NV_STORAGE_VARIABLE_BASE;\r | |
167 | ASSERT (NvStorageBase != 0);\r | |
168 | \r | |
169 | //\r | |
170 | // Copy NV storage data to the memory buffer.\r | |
171 | //\r | |
1436aea4 | 172 | CopyMem (NvStorageData, (UINT8 *)(UINTN)NvStorageBase, NvStorageSize);\r |
6b0d7b01 MK |
173 | \r |
174 | Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r | |
175 | //\r | |
176 | // If FTW protocol has been installed, no need to check FTW last write data hob.\r | |
177 | //\r | |
178 | if (EFI_ERROR (Status)) {\r | |
179 | //\r | |
180 | // Check the FTW last write data hob.\r | |
181 | //\r | |
182 | GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r | |
183 | if (GuidHob != NULL) {\r | |
1436aea4 | 184 | FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *)GET_GUID_HOB_DATA (GuidHob);\r |
6b0d7b01 | 185 | if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r |
1436aea4 | 186 | DEBUG ((DEBUG_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN)FtwLastWriteData->SpareAddress));\r |
6b0d7b01 MK |
187 | //\r |
188 | // Copy the backed up NV storage data to the memory buffer from spare block.\r | |
189 | //\r | |
1436aea4 | 190 | CopyMem (NvStorageData, (UINT8 *)(UINTN)(FtwLastWriteData->SpareAddress), NvStorageSize);\r |
6b0d7b01 | 191 | } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r |
1436aea4 MK |
192 | (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize)))\r |
193 | {\r | |
6b0d7b01 MK |
194 | //\r |
195 | // Flash NV storage from the Offset is backed up in spare block.\r | |
196 | //\r | |
1436aea4 MK |
197 | BackUpOffset = (UINT32)(FtwLastWriteData->TargetAddress - NvStorageBase);\r |
198 | BackUpSize = NvStorageSize - BackUpOffset;\r | |
199 | 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 |
200 | //\r |
201 | // Copy the partial backed up NV storage data to the memory buffer from spare block.\r | |
202 | //\r | |
1436aea4 | 203 | CopyMem (NvStorageData + BackUpOffset, (UINT8 *)(UINTN)FtwLastWriteData->SpareAddress, BackUpSize);\r |
6b0d7b01 MK |
204 | }\r |
205 | }\r | |
206 | }\r | |
207 | \r | |
1436aea4 | 208 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NvStorageData;\r |
6b0d7b01 MK |
209 | \r |
210 | //\r | |
211 | // Check if the Firmware Volume is not corrupted\r | |
212 | //\r | |
213 | if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r | |
214 | FreePool (NvStorageData);\r | |
215 | DEBUG ((DEBUG_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r | |
216 | return EFI_VOLUME_CORRUPTED;\r | |
217 | }\r | |
218 | \r | |
1436aea4 | 219 | VariableStore = (VARIABLE_STORE_HEADER *)((UINTN)FvHeader + FvHeader->HeaderLength);\r |
6b0d7b01 MK |
220 | VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;\r |
221 | ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r | |
222 | ASSERT (VariableStore->Size == VariableStoreLength);\r | |
223 | \r | |
224 | //\r | |
225 | // Check if the Variable Store header is not corrupted\r | |
226 | //\r | |
227 | if (GetVariableStoreStatus (VariableStore) != EfiValid) {\r | |
228 | FreePool (NvStorageData);\r | |
1436aea4 | 229 | DEBUG ((DEBUG_ERROR, "Variable Store header is corrupted\n"));\r |
6b0d7b01 MK |
230 | return EFI_VOLUME_CORRUPTED;\r |
231 | }\r | |
232 | \r | |
233 | mNvFvHeaderCache = FvHeader;\r | |
234 | \r | |
1436aea4 | 235 | *VariableStoreBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStore;\r |
6b0d7b01 | 236 | \r |
1436aea4 MK |
237 | HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r |
238 | MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r | |
6b0d7b01 MK |
239 | BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\r |
240 | \r | |
241 | //\r | |
242 | // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r | |
243 | // is stored with common variable in the same NV region. So the platform integrator should\r | |
244 | // ensure that the value of PcdHwErrStorageSize is less than the value of\r | |
245 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r | |
246 | //\r | |
247 | ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r | |
248 | //\r | |
249 | // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r | |
250 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r | |
251 | //\r | |
252 | ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r | |
253 | //\r | |
254 | // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r | |
255 | // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r | |
256 | //\r | |
257 | ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r | |
258 | \r | |
1436aea4 | 259 | mVariableModuleGlobal->CommonVariableSpace = ((UINTN)VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r |
6b0d7b01 MK |
260 | mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r |
261 | mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r | |
262 | \r | |
263 | DEBUG ((\r | |
264 | DEBUG_INFO,\r | |
265 | "Variable driver common space: 0x%x 0x%x 0x%x\n",\r | |
266 | mVariableModuleGlobal->CommonVariableSpace,\r | |
267 | mVariableModuleGlobal->CommonMaxUserVariableSpace,\r | |
268 | mVariableModuleGlobal->CommonRuntimeVariableSpace\r | |
269 | ));\r | |
270 | \r | |
271 | //\r | |
272 | // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r | |
273 | //\r | |
274 | ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r | |
275 | \r | |
276 | return EFI_SUCCESS;\r | |
277 | }\r | |
278 | \r | |
279 | /**\r | |
280 | Init non-volatile variable store.\r | |
281 | \r | |
282 | @retval EFI_SUCCESS Function successfully executed.\r | |
283 | @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r | |
284 | @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r | |
285 | \r | |
286 | **/\r | |
287 | EFI_STATUS\r | |
288 | InitNonVolatileVariableStore (\r | |
289 | VOID\r | |
290 | )\r | |
291 | {\r | |
1436aea4 MK |
292 | VARIABLE_HEADER *Variable;\r |
293 | VARIABLE_HEADER *NextVariable;\r | |
294 | EFI_PHYSICAL_ADDRESS VariableStoreBase;\r | |
295 | UINTN VariableSize;\r | |
296 | EFI_STATUS Status;\r | |
6b0d7b01 MK |
297 | \r |
298 | if (PcdGetBool (PcdEmuVariableNvModeEnable)) {\r | |
299 | Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);\r | |
300 | if (EFI_ERROR (Status)) {\r | |
301 | return Status;\r | |
302 | }\r | |
1436aea4 | 303 | \r |
6b0d7b01 MK |
304 | mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;\r |
305 | DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));\r | |
306 | } else {\r | |
307 | Status = InitRealNonVolatileVariableStore (&VariableStoreBase);\r | |
308 | if (EFI_ERROR (Status)) {\r | |
309 | return Status;\r | |
310 | }\r | |
1436aea4 | 311 | \r |
6b0d7b01 MK |
312 | mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;\r |
313 | }\r | |
314 | \r | |
315 | mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r | |
1436aea4 MK |
316 | mNvVariableCache = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r |
317 | mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));\r | |
6b0d7b01 | 318 | \r |
1436aea4 | 319 | mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);\r |
6b0d7b01 MK |
320 | mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);\r |
321 | \r | |
322 | //\r | |
323 | // Parse non-volatile variable data and get last variable offset.\r | |
324 | //\r | |
1436aea4 | 325 | Variable = GetStartPointer (mNvVariableCache);\r |
6b0d7b01 MK |
326 | while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r |
327 | NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);\r | |
1436aea4 | 328 | VariableSize = (UINTN)NextVariable - (UINTN)Variable;\r |
6b0d7b01 MK |
329 | if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r |
330 | mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r | |
331 | } else {\r | |
332 | mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r | |
333 | }\r | |
334 | \r | |
335 | Variable = NextVariable;\r | |
336 | }\r | |
1436aea4 MK |
337 | \r |
338 | mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)Variable - (UINTN)mNvVariableCache;\r | |
6b0d7b01 MK |
339 | \r |
340 | return EFI_SUCCESS;\r | |
341 | }\r |