]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/UpdateWorkingBlock.c
Check status before reporting error status code.
[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
d379cbc7 169 UINTN RemainingSpaceSize;\r
85e923a5
LG
170\r
171 //\r
172 // Initialize WorkSpace as FTW_ERASED_BYTE\r
173 //\r
174 SetMem (\r
175 FtwDevice->FtwWorkSpace,\r
176 FtwDevice->FtwWorkSpaceSize,\r
177 FTW_ERASED_BYTE\r
178 );\r
179\r
180 //\r
181 // Read from working block\r
182 //\r
183 Length = FtwDevice->FtwWorkSpaceSize;\r
184 Status = FtwDevice->FtwFvBlock->Read (\r
185 FtwDevice->FtwFvBlock,\r
186 FtwDevice->FtwWorkSpaceLba,\r
187 FtwDevice->FtwWorkSpaceBase,\r
188 &Length,\r
189 FtwDevice->FtwWorkSpace\r
190 );\r
191 if (EFI_ERROR (Status)) {\r
192 return EFI_ABORTED;\r
193 }\r
194 //\r
195 // Refresh the FtwLastWriteHeader\r
196 //\r
197 Status = FtwGetLastWriteHeader (\r
198 FtwDevice->FtwWorkSpaceHeader,\r
199 FtwDevice->FtwWorkSpaceSize,\r
200 &FtwDevice->FtwLastWriteHeader\r
201 );\r
d379cbc7
SZ
202 RemainingSpaceSize = FtwDevice->FtwWorkSpaceSize - ((UINTN) FtwDevice->FtwLastWriteHeader - (UINTN) FtwDevice->FtwWorkSpace);\r
203 DEBUG ((EFI_D_INFO, "Ftw: Remaining work space size - %x\n", RemainingSpaceSize));\r
204 //\r
205 // If FtwGetLastWriteHeader() returns error, or the remaining space size is even not enough to contain\r
206 // one EFI_FAULT_TOLERANT_WRITE_HEADER + one EFI_FAULT_TOLERANT_WRITE_RECORD(It will cause that the header\r
207 // pointed by FtwDevice->FtwLastWriteHeader or record pointed by FtwDevice->FtwLastWriteRecord may contain invalid data),\r
208 // it needs to reclaim work space.\r
209 //\r
210 if (EFI_ERROR (Status) || RemainingSpaceSize < sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER) + sizeof (EFI_FAULT_TOLERANT_WRITE_RECORD)) {\r
85e923a5
LG
211 //\r
212 // reclaim work space in working block.\r
213 //\r
214 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
215 if (EFI_ERROR (Status)) {\r
216 DEBUG ((EFI_D_ERROR, "Ftw: Reclaim workspace - %r\n", Status));\r
217 return EFI_ABORTED;\r
218 }\r
219 //\r
220 // Read from working block again\r
221 //\r
222 Length = FtwDevice->FtwWorkSpaceSize;\r
223 Status = FtwDevice->FtwFvBlock->Read (\r
224 FtwDevice->FtwFvBlock,\r
225 FtwDevice->FtwWorkSpaceLba,\r
226 FtwDevice->FtwWorkSpaceBase,\r
227 &Length,\r
228 FtwDevice->FtwWorkSpace\r
229 );\r
230 if (EFI_ERROR (Status)) {\r
231 return EFI_ABORTED;\r
232 }\r
233\r
234 Status = FtwGetLastWriteHeader (\r
235 FtwDevice->FtwWorkSpaceHeader,\r
236 FtwDevice->FtwWorkSpaceSize,\r
237 &FtwDevice->FtwLastWriteHeader\r
238 );\r
d26c7e82
SZ
239 if (EFI_ERROR (Status)) {\r
240 return EFI_ABORTED;\r
241 }\r
85e923a5
LG
242 }\r
243 //\r
244 // Refresh the FtwLastWriteRecord\r
245 //\r
246 Status = FtwGetLastWriteRecord (\r
247 FtwDevice->FtwLastWriteHeader,\r
248 &FtwDevice->FtwLastWriteRecord\r
249 );\r
250 if (EFI_ERROR (Status)) {\r
251 return EFI_ABORTED;\r
252 }\r
253\r
254 return EFI_SUCCESS;\r
255}\r
256\r
257/**\r
258 Reclaim the work space on the working block.\r
259\r
260 @param FtwDevice Point to private data of FTW driver\r
261 @param PreserveRecord Whether to preserve the working record is needed\r
262\r
263 @retval EFI_SUCCESS The function completed successfully\r
264 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
265 @retval EFI_ABORTED The function could not complete successfully\r
266\r
267**/\r
268EFI_STATUS\r
269FtwReclaimWorkSpace (\r
270 IN EFI_FTW_DEVICE *FtwDevice,\r
271 IN BOOLEAN PreserveRecord\r
272 )\r
273{\r
274 EFI_STATUS Status;\r
275 UINTN Length;\r
276 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
277 UINT8 *TempBuffer;\r
278 UINTN TempBufferSize;\r
279 UINTN SpareBufferSize;\r
280 UINT8 *SpareBuffer;\r
281 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
282 UINTN Index;\r
283 UINT8 *Ptr;\r
d26c7e82 284 EFI_LBA WorkSpaceLbaOffset;\r
85e923a5
LG
285\r
286 DEBUG ((EFI_D_ERROR, "Ftw: start to reclaim work space\n"));\r
287\r
d26c7e82
SZ
288 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
289\r
85e923a5
LG
290 //\r
291 // Read all original data from working block to a memory buffer\r
292 //\r
293 TempBufferSize = FtwDevice->SpareAreaLength;\r
294 TempBuffer = AllocateZeroPool (TempBufferSize);\r
295 if (TempBuffer == NULL) {\r
296 return EFI_OUT_OF_RESOURCES;\r
297 }\r
298\r
299 Ptr = TempBuffer;\r
300 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
301 Length = FtwDevice->BlockSize;\r
302 Status = FtwDevice->FtwFvBlock->Read (\r
303 FtwDevice->FtwFvBlock,\r
304 FtwDevice->FtwWorkBlockLba + Index,\r
305 0,\r
306 &Length,\r
307 Ptr\r
308 );\r
309 if (EFI_ERROR (Status)) {\r
310 FreePool (TempBuffer);\r
311 return EFI_ABORTED;\r
312 }\r
313\r
314 Ptr += Length;\r
315 }\r
316 //\r
317 // Clean up the workspace, remove all the completed records.\r
318 //\r
319 Ptr = TempBuffer +\r
d26c7e82 320 (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
85e923a5
LG
321 FtwDevice->FtwWorkSpaceBase;\r
322\r
323 //\r
324 // Clear the content of buffer that will save the new work space data\r
325 //\r
326 SetMem (Ptr, FtwDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
327\r
328 //\r
329 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
330 //\r
331 CopyMem (\r
332 Ptr,\r
333 FtwDevice->FtwWorkSpaceHeader,\r
334 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
335 );\r
336 if (PreserveRecord) {\r
337 //\r
338 // Get the last record following the header,\r
339 //\r
340 Status = FtwGetLastWriteHeader (\r
341 FtwDevice->FtwWorkSpaceHeader,\r
342 FtwDevice->FtwWorkSpaceSize,\r
343 &FtwDevice->FtwLastWriteHeader\r
344 );\r
345 Header = FtwDevice->FtwLastWriteHeader;\r
8dc8879a 346 if (!EFI_ERROR (Status) && (Header != NULL) && (Header->Complete != FTW_VALID_STATE) && (Header->HeaderAllocated == FTW_VALID_STATE)) {\r
85e923a5
LG
347 CopyMem (\r
348 Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
349 FtwDevice->FtwLastWriteHeader,\r
350 WRITE_TOTAL_SIZE (Header->NumberOfWrites, Header->PrivateDataSize)\r
351 );\r
352 }\r
353 }\r
354\r
355 CopyMem (\r
356 FtwDevice->FtwWorkSpace,\r
357 Ptr,\r
358 FtwDevice->FtwWorkSpaceSize\r
359 );\r
360\r
361 FtwGetLastWriteHeader (\r
362 FtwDevice->FtwWorkSpaceHeader,\r
363 FtwDevice->FtwWorkSpaceSize,\r
364 &FtwDevice->FtwLastWriteHeader\r
365 );\r
366\r
d26c7e82
SZ
367 FtwGetLastWriteRecord (\r
368 FtwDevice->FtwLastWriteHeader,\r
369 &FtwDevice->FtwLastWriteRecord\r
370 );\r
371\r
85e923a5
LG
372 //\r
373 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
374 //\r
d26c7e82
SZ
375 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) (TempBuffer +\r
376 (UINTN) WorkSpaceLbaOffset * FtwDevice->BlockSize +\r
377 FtwDevice->FtwWorkSpaceBase);\r
85e923a5
LG
378 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
379 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
380\r
381 //\r
382 // Try to keep the content of spare block\r
383 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
384 //\r
385 SpareBufferSize = FtwDevice->SpareAreaLength;\r
386 SpareBuffer = AllocatePool (SpareBufferSize);\r
387 if (SpareBuffer == NULL) {\r
388 FreePool (TempBuffer);\r
389 return EFI_OUT_OF_RESOURCES;\r
390 }\r
391\r
392 Ptr = SpareBuffer;\r
393 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
394 Length = FtwDevice->BlockSize;\r
395 Status = FtwDevice->FtwBackupFvb->Read (\r
396 FtwDevice->FtwBackupFvb,\r
397 FtwDevice->FtwSpareLba + Index,\r
398 0,\r
399 &Length,\r
400 Ptr\r
401 );\r
402 if (EFI_ERROR (Status)) {\r
403 FreePool (TempBuffer);\r
404 FreePool (SpareBuffer);\r
405 return EFI_ABORTED;\r
406 }\r
407\r
408 Ptr += Length;\r
409 }\r
410 //\r
411 // Write the memory buffer to spare block\r
412 //\r
413 Status = FtwEraseSpareBlock (FtwDevice);\r
414 Ptr = TempBuffer;\r
415 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
416 Length = FtwDevice->BlockSize;\r
417 Status = FtwDevice->FtwBackupFvb->Write (\r
418 FtwDevice->FtwBackupFvb,\r
419 FtwDevice->FtwSpareLba + Index,\r
420 0,\r
421 &Length,\r
422 Ptr\r
423 );\r
424 if (EFI_ERROR (Status)) {\r
425 FreePool (TempBuffer);\r
426 FreePool (SpareBuffer);\r
427 return EFI_ABORTED;\r
428 }\r
429\r
430 Ptr += Length;\r
431 }\r
432 //\r
433 // Free TempBuffer\r
434 //\r
435 FreePool (TempBuffer);\r
436\r
437 //\r
438 // Set the WorkingBlockValid in spare block\r
439 //\r
440 Status = FtwUpdateFvState (\r
441 FtwDevice->FtwBackupFvb,\r
d26c7e82 442 FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
85e923a5
LG
443 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
444 WORKING_BLOCK_VALID\r
445 );\r
446 if (EFI_ERROR (Status)) {\r
447 FreePool (SpareBuffer);\r
448 return EFI_ABORTED;\r
449 }\r
450 //\r
451 // Before erase the working block, set WorkingBlockInvalid in working block.\r
452 //\r
453 // Offset = OFFSET_OF(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER,\r
454 // WorkingBlockInvalid);\r
455 //\r
456 Status = FtwUpdateFvState (\r
457 FtwDevice->FtwFvBlock,\r
458 FtwDevice->FtwWorkSpaceLba,\r
459 FtwDevice->FtwWorkSpaceBase + sizeof (EFI_GUID) + sizeof (UINT32),\r
460 WORKING_BLOCK_INVALID\r
461 );\r
462 if (EFI_ERROR (Status)) {\r
463 FreePool (SpareBuffer);\r
464 return EFI_ABORTED;\r
465 }\r
466\r
467 FtwDevice->FtwWorkSpaceHeader->WorkingBlockInvalid = FTW_VALID_STATE;\r
468\r
469 //\r
470 // Write the spare block to working block\r
471 //\r
472 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
473 if (EFI_ERROR (Status)) {\r
474 FreePool (SpareBuffer);\r
475 return Status;\r
476 }\r
477 //\r
478 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
479 //\r
480 Status = FtwEraseSpareBlock (FtwDevice);\r
481 Ptr = SpareBuffer;\r
482 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
483 Length = FtwDevice->BlockSize;\r
484 Status = FtwDevice->FtwBackupFvb->Write (\r
485 FtwDevice->FtwBackupFvb,\r
486 FtwDevice->FtwSpareLba + Index,\r
487 0,\r
488 &Length,\r
489 Ptr\r
490 );\r
491 if (EFI_ERROR (Status)) {\r
492 FreePool (SpareBuffer);\r
493 return EFI_ABORTED;\r
494 }\r
495\r
496 Ptr += Length;\r
497 }\r
498\r
499 FreePool (SpareBuffer);\r
500\r
501 DEBUG ((EFI_D_ERROR, "Ftw: reclaim work space successfully\n"));\r
502\r
503 return EFI_SUCCESS;\r
504}\r