]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
Add more exact SMM check in SmmFaultTolerantWriteHandler.
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / UpdateWorkingBlock.c
CommitLineData
85e923a5
LG
1/** @file\r
2\r
3 Internal functions to operate Working Block Space.\r
4\r
d26c7e82 5Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 6This program and the accompanying materials \r
85e923a5
LG
7are licensed and made available under the terms and conditions of the BSD License \r
8which accompanies this distribution. The full text of the license may be found at \r
9http://opensource.org/licenses/bsd-license.php \r
10 \r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
13\r
14**/\r
15\r
16\r
17#include "FaultTolerantWrite.h"\r
18\r
19/**\r
20 Check to see if it is a valid work space.\r
21\r
22\r
23 @param WorkingHeader Pointer of working block header\r
24\r
d26c7e82
SZ
25 @retval TRUE The work space is valid.\r
26 @retval FALSE The work space is invalid.\r
85e923a5
LG
27\r
28**/\r
29BOOLEAN\r
30IsValidWorkSpace (\r
31 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
32 )\r
33{\r
34 EFI_STATUS Status;\r
35 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
36\r
37 if (WorkingHeader == NULL) {\r
38 return FALSE;\r
39 }\r
40\r
41 if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
42 DEBUG ((EFI_D_ERROR, "Ftw: Work block header valid bit check error\n"));\r
43 return FALSE;\r
44 }\r
45 //\r
46 // Check signature with gEfiSystemNvDataFvGuid\r
47 //\r
48 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
49 DEBUG ((EFI_D_ERROR, "Ftw: Work block header signature check error\n"));\r
50 return FALSE;\r
51 }\r
52 //\r
53 // Check the CRC of header\r
54 //\r
55 CopyMem (\r
56 &WorkingBlockHeader,\r
57 WorkingHeader,\r
58 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
59 );\r
60\r
61 //\r
62 // Filter out the Crc and State fields\r
63 //\r
64 SetMem (\r
65 &WorkingBlockHeader.Crc,\r
66 sizeof (UINT32),\r
67 FTW_ERASED_BYTE\r
68 );\r
69 WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;\r
70 WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
71\r
72 //\r
73 // Calculate the Crc of woking block header\r
74 //\r
75 Status = gBS->CalculateCrc32 (\r
76 (UINT8 *) &WorkingBlockHeader,\r
77 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
78 &WorkingBlockHeader.Crc\r
79 );\r
80 if (EFI_ERROR (Status)) {\r
81 return FALSE;\r
82 }\r
83\r
84 if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
85 DEBUG ((EFI_D_ERROR, "Ftw: Work block header CRC check error\n"));\r
86 return FALSE;\r
87 }\r
88\r
89 return TRUE;\r
90}\r
91\r
92/**\r
93 Initialize a work space when there is no work space.\r
94\r
95 @param WorkingHeader Pointer of working block header\r
96\r
97 @retval EFI_SUCCESS The function completed successfully\r
98 @retval EFI_ABORTED The function could not complete successfully.\r
99\r
100**/\r
101EFI_STATUS\r
102InitWorkSpaceHeader (\r
103 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
104 )\r
105{\r
106 EFI_STATUS Status;\r
107\r
108 if (WorkingHeader == NULL) {\r
109 return EFI_INVALID_PARAMETER;\r
110 }\r
111 //\r
112 // Here using gEfiSystemNvDataFvGuid as the signature.\r
113 //\r
114 CopyMem (\r
115 &WorkingHeader->Signature,\r
116 &gEfiSystemNvDataFvGuid,\r
117 sizeof (EFI_GUID)\r
118 );\r
119 WorkingHeader->WriteQueueSize = (UINT64) (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) - sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER));\r
120\r
121 //\r
122 // Crc is calculated with all the fields except Crc and STATE\r
123 //\r
124 WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
125 WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
126\r
127 SetMem (\r
128 &WorkingHeader->Crc,\r
129 sizeof (UINT32),\r
130 FTW_ERASED_BYTE\r
131 );\r
132\r
133 //\r
134 // Calculate the CRC value\r
135 //\r
136 Status = gBS->CalculateCrc32 (\r
137 (UINT8 *) WorkingHeader,\r
138 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
139 &WorkingHeader->Crc\r
140 );\r
141 if (EFI_ERROR (Status)) {\r
142 return EFI_ABORTED;\r
143 }\r
144 //\r
145 // Restore the WorkingBlockValid flag to VALID state\r
146 //\r
147 WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
148 WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
149\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153/**\r
154 Read from working block to refresh the work space in memory.\r
155\r
156 @param FtwDevice Point to private data of FTW driver\r
157\r
158 @retval EFI_SUCCESS The function completed successfully\r
159 @retval EFI_ABORTED The function could not complete successfully.\r
160\r
161**/\r
162EFI_STATUS\r
163WorkSpaceRefresh (\r
164 IN EFI_FTW_DEVICE *FtwDevice\r
165 )\r
166{\r
167 EFI_STATUS Status;\r
168 UINTN Length;\r
85e923a5
LG
169\r
170 //\r
171 // Initialize WorkSpace as FTW_ERASED_BYTE\r
172 //\r
173 SetMem (\r
174 FtwDevice->FtwWorkSpace,\r
175 FtwDevice->FtwWorkSpaceSize,\r
176 FTW_ERASED_BYTE\r
177 );\r
178\r
179 //\r
180 // Read from working block\r
181 //\r
182 Length = FtwDevice->FtwWorkSpaceSize;\r
183 Status = FtwDevice->FtwFvBlock->Read (\r
184 FtwDevice->FtwFvBlock,\r
185 FtwDevice->FtwWorkSpaceLba,\r
186 FtwDevice->FtwWorkSpaceBase,\r
187 &Length,\r
188 FtwDevice->FtwWorkSpace\r
189 );\r
190 if (EFI_ERROR (Status)) {\r
191 return EFI_ABORTED;\r
192 }\r
193 //\r
194 // Refresh the FtwLastWriteHeader\r
195 //\r
196 Status = FtwGetLastWriteHeader (\r
197 FtwDevice->FtwWorkSpaceHeader,\r
198 FtwDevice->FtwWorkSpaceSize,\r
199 &FtwDevice->FtwLastWriteHeader\r
200 );\r
d26c7e82 201 if (EFI_ERROR (Status)) {\r
85e923a5
LG
202 //\r
203 // reclaim work space in working block.\r
204 //\r
205 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
206 if (EFI_ERROR (Status)) {\r
207 DEBUG ((EFI_D_ERROR, "Ftw: Reclaim workspace - %r\n", Status));\r
208 return EFI_ABORTED;\r
209 }\r
210 //\r
211 // Read from working block again\r
212 //\r
213 Length = FtwDevice->FtwWorkSpaceSize;\r
214 Status = FtwDevice->FtwFvBlock->Read (\r
215 FtwDevice->FtwFvBlock,\r
216 FtwDevice->FtwWorkSpaceLba,\r
217 FtwDevice->FtwWorkSpaceBase,\r
218 &Length,\r
219 FtwDevice->FtwWorkSpace\r
220 );\r
221 if (EFI_ERROR (Status)) {\r
222 return EFI_ABORTED;\r
223 }\r
224\r
225 Status = FtwGetLastWriteHeader (\r
226 FtwDevice->FtwWorkSpaceHeader,\r
227 FtwDevice->FtwWorkSpaceSize,\r
228 &FtwDevice->FtwLastWriteHeader\r
229 );\r
d26c7e82
SZ
230 if (EFI_ERROR (Status)) {\r
231 return EFI_ABORTED;\r
232 }\r
85e923a5
LG
233 }\r
234 //\r
235 // Refresh the FtwLastWriteRecord\r
236 //\r
237 Status = FtwGetLastWriteRecord (\r
238 FtwDevice->FtwLastWriteHeader,\r
239 &FtwDevice->FtwLastWriteRecord\r
240 );\r
241 if (EFI_ERROR (Status)) {\r
242 return EFI_ABORTED;\r
243 }\r
244\r
245 return EFI_SUCCESS;\r
246}\r
247\r
248/**\r
249 Reclaim the work space on the working block.\r
250\r
251 @param FtwDevice Point to private data of FTW driver\r
252 @param PreserveRecord Whether to preserve the working record is needed\r
253\r
254 @retval EFI_SUCCESS The function completed successfully\r
255 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
256 @retval EFI_ABORTED The function could not complete successfully\r
257\r
258**/\r
259EFI_STATUS\r
260FtwReclaimWorkSpace (\r
261 IN EFI_FTW_DEVICE *FtwDevice,\r
262 IN BOOLEAN PreserveRecord\r
263 )\r
264{\r
265 EFI_STATUS Status;\r
266 UINTN Length;\r
267 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
268 UINT8 *TempBuffer;\r
269 UINTN TempBufferSize;\r
270 UINTN SpareBufferSize;\r
271 UINT8 *SpareBuffer;\r
272 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
273 UINTN Index;\r
274 UINT8 *Ptr;\r
d26c7e82 275 EFI_LBA WorkSpaceLbaOffset;\r
85e923a5
LG
276\r
277 DEBUG ((EFI_D_ERROR, "Ftw: start to reclaim work space\n"));\r
278\r
d26c7e82
SZ
279 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
280\r
85e923a5
LG
281 //\r
282 // Read all original data from working block to a memory buffer\r
283 //\r
284 TempBufferSize = FtwDevice->SpareAreaLength;\r
285 TempBuffer = AllocateZeroPool (TempBufferSize);\r
286 if (TempBuffer == NULL) {\r
287 return EFI_OUT_OF_RESOURCES;\r
288 }\r
289\r
290 Ptr = TempBuffer;\r
291 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
292 Length = FtwDevice->BlockSize;\r
293 Status = FtwDevice->FtwFvBlock->Read (\r
294 FtwDevice->FtwFvBlock,\r
295 FtwDevice->FtwWorkBlockLba + Index,\r
296 0,\r
297 &Length,\r
298 Ptr\r
299 );\r
300 if (EFI_ERROR (Status)) {\r
301 FreePool (TempBuffer);\r
302 return EFI_ABORTED;\r
303 }\r
304\r
305 Ptr += Length;\r
306 }\r
307 //\r
308 // Clean up the workspace, remove all the completed records.\r
309 //\r
310 Ptr = TempBuffer +\r
d26c7e82 311 (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
85e923a5
LG
312 FtwDevice->FtwWorkSpaceBase;\r
313\r
314 //\r
315 // Clear the content of buffer that will save the new work space data\r
316 //\r
317 SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
318\r
319 //\r
320 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
321 //\r
322 CopyMem (\r
323 Ptr,\r
324 FtwDevice->FtwWorkSpaceHeader,\r
325 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
326 );\r
327 if (PreserveRecord) {\r
328 //\r
329 // Get the last record following the header,\r
330 //\r
331 Status = FtwGetLastWriteHeader (\r
332 FtwDevice->FtwWorkSpaceHeader,\r
333 FtwDevice->FtwWorkSpaceSize,\r
334 &FtwDevice->FtwLastWriteHeader\r
335 );\r
336 Header = FtwDevice->FtwLastWriteHeader;\r
8dc8879a 337 if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {\r
85e923a5
LG
338 CopyMem (\r
339 Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
340 FtwDevice->FtwLastWriteHeader,\r
341 WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
342 );\r
343 }\r
344 }\r
345\r
346 CopyMem (\r
347 FtwDevice->FtwWorkSpace,\r
348 Ptr,\r
349 FtwDevice->FtwWorkSpaceSize\r
350 );\r
351\r
352 FtwGetLastWriteHeader (\r
353 FtwDevice->FtwWorkSpaceHeader,\r
354 FtwDevice->FtwWorkSpaceSize,\r
355 &FtwDevice->FtwLastWriteHeader\r
356 );\r
357\r
d26c7e82
SZ
358 FtwGetLastWriteRecord (\r
359 FtwDevice->FtwLastWriteHeader,\r
360 &FtwDevice->FtwLastWriteRecord\r
361 );\r
362\r
85e923a5
LG
363 //\r
364 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
365 //\r
d26c7e82
SZ
366 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +\r
367 (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
368 FtwDevice->FtwWorkSpaceBase);\r
85e923a5
LG
369 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
370 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
371\r
372 //\r
373 // Try to keep the content of spare block\r
374 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
375 //\r
376 SpareBufferSize = FtwDevice->SpareAreaLength;\r
377 SpareBuffer = AllocatePool (SpareBufferSize);\r
378 if (SpareBuffer == NULL) {\r
379 FreePool (TempBuffer);\r
380 return EFI_OUT_OF_RESOURCES;\r
381 }\r
382\r
383 Ptr = SpareBuffer;\r
384 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
385 Length = FtwDevice->BlockSize;\r
386 Status = FtwDevice->FtwBackupFvb->Read (\r
387 FtwDevice->FtwBackupFvb,\r
388 FtwDevice->FtwSpareLba + Index,\r
389 0,\r
390 &Length,\r
391 Ptr\r
392 );\r
393 if (EFI_ERROR (Status)) {\r
394 FreePool (TempBuffer);\r
395 FreePool (SpareBuffer);\r
396 return EFI_ABORTED;\r
397 }\r
398\r
399 Ptr += Length;\r
400 }\r
401 //\r
402 // Write the memory buffer to spare block\r
403 //\r
404 Status = FtwEraseSpareBlock (FtwDevice);\r
405 Ptr = TempBuffer;\r
406 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
407 Length = FtwDevice->BlockSize;\r
408 Status = FtwDevice->FtwBackupFvb->Write (\r
409 FtwDevice->FtwBackupFvb,\r
410 FtwDevice->FtwSpareLba + Index,\r
411 0,\r
412 &Length,\r
413 Ptr\r
414 );\r
415 if (EFI_ERROR (Status)) {\r
416 FreePool (TempBuffer);\r
417 FreePool (SpareBuffer);\r
418 return EFI_ABORTED;\r
419 }\r
420\r
421 Ptr += Length;\r
422 }\r
423 //\r
424 // Free TempBuffer\r
425 //\r
426 FreePool (TempBuffer);\r
427\r
428 //\r
429 // Set the WorkingBlockValid in spare block\r
430 //\r
431 Status = FtwUpdateFvState (\r
432 FtwDevice->FtwBackupFvb,\r
d26c7e82 433 FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
85e923a5
LG
434 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
435 WORKING_BLOCK_VALID\r
436 );\r
437 if (EFI_ERROR (Status)) {\r
438 FreePool (SpareBuffer);\r
439 return EFI_ABORTED;\r
440 }\r
441 //\r
442 // Before erase the working block, set WorkingBlockInvalid in working block.\r
443 //\r
444 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
445 // WorkingBlockInvalid);\r
446 //\r
447 Status = FtwUpdateFvState (\r
448 FtwDevice->FtwFvBlock,\r
449 FtwDevice->FtwWorkSpaceLba,\r
450 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
451 WORKING_BLOCK_INVALID\r
452 );\r
453 if (EFI_ERROR (Status)) {\r
454 FreePool (SpareBuffer);\r
455 return EFI_ABORTED;\r
456 }\r
457\r
458 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
459\r
460 //\r
461 // Write the spare block to working block\r
462 //\r
463 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
464 if (EFI_ERROR (Status)) {\r
465 FreePool (SpareBuffer);\r
466 return Status;\r
467 }\r
468 //\r
469 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
470 //\r
471 Status = FtwEraseSpareBlock (FtwDevice);\r
472 Ptr = SpareBuffer;\r
473 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
474 Length = FtwDevice->BlockSize;\r
475 Status = FtwDevice->FtwBackupFvb->Write (\r
476 FtwDevice->FtwBackupFvb,\r
477 FtwDevice->FtwSpareLba + Index,\r
478 0,\r
479 &Length,\r
480 Ptr\r
481 );\r
482 if (EFI_ERROR (Status)) {\r
483 FreePool (SpareBuffer);\r
484 return EFI_ABORTED;\r
485 }\r
486\r
487 Ptr += Length;\r
488 }\r
489\r
490 FreePool (SpareBuffer);\r
491\r
492 DEBUG ((EFI_D_ERROR, "Ftw: reclaim work space successfully\n"));\r
493\r
494 return EFI_SUCCESS;\r
495}\r