]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FirmwareVolume/FaultTolerantWriteDxe/FtwWorkSpace.c
modify coding style to pass ecc tool
[mirror_edk2.git] / MdeModulePkg / Universal / FirmwareVolume / FaultTolerantWriteDxe / FtwWorkSpace.c
CommitLineData
6cc9ca32 1/** @file\r
d7dec593 2\r
6cc9ca32
LG
3 Internal functions to operate Working Block Space.\r
4\r
5Copyright (c) 2006 - 2008, Intel Corporation \r
d7dec593 6All rights reserved. This program and the accompanying materials \r
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
6cc9ca32 14**/\r
d7dec593 15\r
16\r
17#include <FtwLite.h>\r
18\r
6aab8214 19/**\r
20 Check to see if it is a valid work space.\r
d7dec593 21\r
d7dec593 22\r
6aab8214 23 @param WorkingHeader Pointer of working block header\r
d7dec593 24\r
6aab8214 25 @retval EFI_SUCCESS The function completed successfully\r
26 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 27\r
6aab8214 28**/\r
29BOOLEAN\r
30IsValidWorkSpace (\r
31 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
32 )\r
d7dec593 33{\r
34 EFI_STATUS Status;\r
35 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER WorkingBlockHeader;\r
36\r
37 ASSERT (WorkingHeader != NULL);\r
38 if (WorkingHeader->WorkingBlockValid != FTW_VALID_STATE) {\r
39 return FALSE;\r
40 }\r
41 //\r
42 // Check signature with gEfiSystemNvDataFvGuid\r
43 //\r
44 if (!CompareGuid (&gEfiSystemNvDataFvGuid, &WorkingHeader->Signature)) {\r
45 return FALSE;\r
46 }\r
47 //\r
48 // Check the CRC of header\r
49 //\r
50 CopyMem (\r
51 &WorkingBlockHeader,\r
52 WorkingHeader,\r
53 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
54 );\r
55\r
56 //\r
57 // Filter out the Crc and State fields\r
58 //\r
59 SetMem (\r
60 &WorkingBlockHeader.Crc,\r
61 sizeof (UINT32),\r
62 FTW_ERASED_BYTE\r
63 );\r
64 WorkingBlockHeader.WorkingBlockValid = FTW_ERASE_POLARITY;\r
65 WorkingBlockHeader.WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
66\r
67 //\r
68 // Calculate the Crc of woking block header\r
69 //\r
70 Status = gBS->CalculateCrc32 (\r
71 (UINT8 *) &WorkingBlockHeader,\r
72 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
73 &WorkingBlockHeader.Crc\r
74 );\r
75 ASSERT_EFI_ERROR (Status);\r
76\r
77 if (WorkingBlockHeader.Crc != WorkingHeader->Crc) {\r
78 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Work block header CRC check error\n"));\r
79 return FALSE;\r
80 }\r
81\r
82 return TRUE;\r
83}\r
84\r
6aab8214 85/**\r
86 Initialize a work space when there is no work space.\r
d7dec593 87\r
d7dec593 88\r
6aab8214 89 @param WorkingHeader Pointer of working block header\r
d7dec593 90\r
6aab8214 91 @retval EFI_SUCCESS The function completed successfully\r
92 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 93\r
6aab8214 94**/\r
95EFI_STATUS\r
96InitWorkSpaceHeader (\r
97 IN EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingHeader\r
98 )\r
d7dec593 99{\r
100 EFI_STATUS Status;\r
101\r
102 ASSERT (WorkingHeader != NULL);\r
103\r
104 //\r
105 // Here using gEfiSystemNvDataFvGuid as the signature.\r
106 //\r
107 CopyMem (\r
108 &WorkingHeader->Signature,\r
109 &gEfiSystemNvDataFvGuid,\r
110 sizeof (EFI_GUID)\r
111 );\r
112 WorkingHeader->WriteQueueSize = FTW_WORKING_QUEUE_SIZE;\r
113\r
114 //\r
115 // Crc is calculated with all the fields except Crc and STATE\r
116 //\r
117 WorkingHeader->WorkingBlockValid = FTW_ERASE_POLARITY;\r
118 WorkingHeader->WorkingBlockInvalid = FTW_ERASE_POLARITY;\r
119 SetMem (&WorkingHeader->Crc, sizeof (UINT32), FTW_ERASED_BYTE);\r
120\r
121 //\r
122 // Calculate the CRC value\r
123 //\r
124 Status = gBS->CalculateCrc32 (\r
125 (UINT8 *) WorkingHeader,\r
126 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
127 &WorkingHeader->Crc\r
128 );\r
129 ASSERT_EFI_ERROR (Status);\r
130\r
131 //\r
132 // Restore the WorkingBlockValid flag to VALID state\r
133 //\r
134 WorkingHeader->WorkingBlockValid = FTW_VALID_STATE;\r
135 WorkingHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
136\r
137 return EFI_SUCCESS;\r
138}\r
139\r
6aab8214 140/**\r
141 Update a bit of state on a block device. The location of the bit is\r
142 calculated by the (Lba, Offset, bit). Here bit is determined by the\r
143 the name of a certain bit.\r
144\r
145\r
146 @param FvBlock FVB Protocol interface to access SrcBlock and DestBlock\r
147 @param Lba Lba of a block\r
148 @param Offset Offset on the Lba\r
149 @param NewBit New value that will override the old value if it can be change\r
150\r
151 @retval EFI_SUCCESS A state bit has been updated successfully\r
152 @retval Others Access block device error.\r
153 Notes:\r
154 Assume all bits of State are inside the same BYTE.\r
155 @retval EFI_ABORTED Read block fail\r
156\r
157**/\r
d7dec593 158EFI_STATUS\r
159FtwUpdateFvState (\r
160 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvBlock,\r
161 IN EFI_LBA Lba,\r
162 IN UINTN Offset,\r
163 IN UINT8 NewBit\r
164 )\r
d7dec593 165{\r
166 EFI_STATUS Status;\r
167 UINT8 State;\r
168 UINTN Length;\r
169\r
170 //\r
171 // Read state from device, assume State is only one byte.\r
172 //\r
173 Length = sizeof (UINT8);\r
174 Status = FvBlock->Read (FvBlock, Lba, Offset, &Length, &State);\r
175 if (EFI_ERROR (Status)) {\r
176 return EFI_ABORTED;\r
177 }\r
178\r
179 State ^= FTW_POLARITY_REVERT;\r
180 State = (UINT8) (State | NewBit);\r
181 State ^= FTW_POLARITY_REVERT;\r
182\r
183 //\r
184 // Write state back to device\r
185 //\r
186 Length = sizeof (UINT8);\r
187 Status = FvBlock->Write (FvBlock, Lba, Offset, &Length, &State);\r
188\r
189 return Status;\r
190}\r
191\r
6aab8214 192/**\r
193 Get the last Write record pointer.\r
194 The last record is the record whose 'complete' state hasn't been set.\r
195 After all, this header may be a EMPTY header entry for next Allocate.\r
196\r
197\r
198 @param FtwLiteDevice Private data of this driver\r
199 @param FtwLastRecord Pointer to retrieve the last write record\r
200\r
201 @retval EFI_SUCCESS Get the last write record successfully\r
202 @retval EFI_ABORTED The FTW work space is damaged\r
203\r
204**/\r
d7dec593 205EFI_STATUS\r
206FtwGetLastRecord (\r
207 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
208 OUT EFI_FTW_LITE_RECORD **FtwLastRecord\r
209 )\r
d7dec593 210{\r
211 EFI_FTW_LITE_RECORD *Record;\r
212\r
e11ae3a5 213 *FtwLastRecord = NULL;\r
d7dec593 214 Record = (EFI_FTW_LITE_RECORD *) (FtwLiteDevice->FtwWorkSpaceHeader + 1);\r
215 while (Record->WriteCompleted == FTW_VALID_STATE) {\r
216 //\r
217 // If Offset exceed the FTW work space boudary, return error.\r
218 //\r
219 if ((UINTN) ((UINT8 *) Record - FtwLiteDevice->FtwWorkSpace) > FtwLiteDevice->FtwWorkSpaceSize) {\r
220 return EFI_ABORTED;\r
221 }\r
222\r
223 Record++;\r
224 }\r
225 //\r
226 // Last write record is found\r
227 //\r
228 *FtwLastRecord = Record;\r
229 return EFI_SUCCESS;\r
230}\r
231\r
6aab8214 232/**\r
233 Read from working block to refresh the work space in memory.\r
d7dec593 234\r
d7dec593 235\r
6aab8214 236 @param FtwLiteDevice Point to private data of FTW driver\r
d7dec593 237\r
6aab8214 238 @retval EFI_SUCCESS The function completed successfully\r
239 @retval EFI_ABORTED The function could not complete successfully.\r
d7dec593 240\r
6aab8214 241**/\r
242EFI_STATUS\r
243WorkSpaceRefresh (\r
244 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice\r
245 )\r
d7dec593 246{\r
247 EFI_STATUS Status;\r
248 UINTN Length;\r
249 UINTN Offset;\r
250 EFI_FTW_LITE_RECORD *Record;\r
251\r
252 //\r
253 // Initialize WorkSpace as FTW_ERASED_BYTE\r
254 //\r
255 SetMem (\r
256 FtwLiteDevice->FtwWorkSpace,\r
257 FtwLiteDevice->FtwWorkSpaceSize,\r
258 FTW_ERASED_BYTE\r
259 );\r
260\r
261 //\r
262 // Read from working block\r
263 //\r
264 Length = FtwLiteDevice->FtwWorkSpaceSize;\r
265 Status = FtwLiteDevice->FtwFvBlock->Read (\r
266 FtwLiteDevice->FtwFvBlock,\r
267 FtwLiteDevice->FtwWorkSpaceLba,\r
268 FtwLiteDevice->FtwWorkSpaceBase,\r
269 &Length,\r
270 FtwLiteDevice->FtwWorkSpace\r
271 );\r
272 if (EFI_ERROR (Status)) {\r
273 return EFI_ABORTED;\r
274 }\r
275 //\r
276 // Refresh the FtwLastRecord\r
277 //\r
278 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
279\r
280 Record = FtwLiteDevice->FtwLastRecord;\r
281 Offset = (UINTN) (UINT8 *) Record - (UINTN) FtwLiteDevice->FtwWorkSpace;\r
282\r
283 //\r
284 // IF work space has error or Record is out of the workspace limit, THEN\r
285 // call reclaim.\r
286 //\r
287 if (EFI_ERROR (Status) || (Offset + WRITE_TOTAL_SIZE >= FtwLiteDevice->FtwWorkSpaceSize)) {\r
288 //\r
289 // reclaim work space in working block.\r
290 //\r
e11ae3a5 291 Status = FtwReclaimWorkSpace (FtwLiteDevice, TRUE);\r
d7dec593 292 if (EFI_ERROR (Status)) {\r
293 DEBUG ((EFI_D_FTW_LITE, "FtwLite: Reclaim workspace - %r\n", Status));\r
294 return EFI_ABORTED;\r
295 }\r
296 }\r
297\r
298 return EFI_SUCCESS;\r
299}\r
300\r
6aab8214 301/**\r
302 Reclaim the work space on the working block.\r
d7dec593 303\r
d7dec593 304\r
9920ae74 305 @param FtwLiteDevice Point to private data of FTW driver\r
306 @param PreserveRecord Whether get the last record or not\r
d7dec593 307\r
9920ae74 308 @retval EFI_SUCCESS The function completed successfully\r
309 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
310 @retval EFI_ABORTED The function could not complete successfully\r
d7dec593 311\r
6aab8214 312**/\r
313EFI_STATUS\r
314FtwReclaimWorkSpace (\r
e11ae3a5
LG
315 IN EFI_FTW_LITE_DEVICE *FtwLiteDevice,\r
316 IN BOOLEAN PreserveRecord\r
6aab8214 317 )\r
d7dec593 318{\r
319 EFI_STATUS Status;\r
320 UINT8 *TempBuffer;\r
321 UINTN TempBufferSize;\r
322 UINT8 *Ptr;\r
323 UINTN Length;\r
324 UINTN Index;\r
325 UINTN SpareBufferSize;\r
326 UINT8 *SpareBuffer;\r
327 EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *WorkingBlockHeader;\r
e11ae3a5 328 EFI_FTW_LITE_RECORD *Record;\r
d7dec593 329\r
330 DEBUG ((EFI_D_FTW_LITE, "FtwLite: start to reclaim work space\n"));\r
331\r
332 //\r
333 // Read all original data from working block to a memory buffer\r
334 //\r
335 TempBufferSize = FtwLiteDevice->SpareAreaLength;\r
336 TempBuffer = AllocateZeroPool (TempBufferSize);\r
e11ae3a5 337 if (TempBuffer == NULL) {\r
d7dec593 338 return EFI_OUT_OF_RESOURCES;\r
339 }\r
340\r
341 Ptr = TempBuffer;\r
342 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
343 Length = FtwLiteDevice->SizeOfSpareBlock;\r
344 Status = FtwLiteDevice->FtwFvBlock->Read (\r
345 FtwLiteDevice->FtwFvBlock,\r
346 FtwLiteDevice->FtwWorkBlockLba + Index,\r
347 0,\r
348 &Length,\r
349 Ptr\r
350 );\r
351 if (EFI_ERROR (Status)) {\r
352 FreePool (TempBuffer);\r
353 return EFI_ABORTED;\r
354 }\r
355\r
356 Ptr += Length;\r
357 }\r
358 //\r
359 // Clean up the workspace, remove all the completed records.\r
360 //\r
361 Ptr = TempBuffer +\r
362 ((UINTN) (FtwLiteDevice->FtwWorkSpaceLba - FtwLiteDevice->FtwWorkBlockLba)) *\r
363 FtwLiteDevice->SizeOfSpareBlock + FtwLiteDevice->FtwWorkSpaceBase;\r
364\r
e11ae3a5
LG
365 //\r
366 // Clear the content of buffer that will save the new work space data\r
367 //\r
368 SetMem (Ptr, FtwLiteDevice->FtwWorkSpaceSize, FTW_ERASED_BYTE);\r
369\r
370 //\r
371 // Copy EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER to buffer\r
372 //\r
373 CopyMem (\r
374 Ptr,\r
375 FtwLiteDevice->FtwWorkSpaceHeader,\r
376 sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER)\r
377 );\r
378 if (PreserveRecord) {\r
379 //\r
380 // Get the last record\r
381 //\r
382 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
383 Record = FtwLiteDevice->FtwLastRecord;\r
384 if (!EFI_ERROR (Status) &&\r
385 Record != NULL &&\r
386 Record->WriteAllocated == FTW_VALID_STATE &&\r
387 Record->WriteCompleted != FTW_VALID_STATE) {\r
388 CopyMem (\r
389 (UINT8 *) Ptr + sizeof (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER),\r
390 Record,\r
391 WRITE_TOTAL_SIZE\r
392 );\r
393 }\r
394 }\r
d7dec593 395\r
396 CopyMem (\r
397 FtwLiteDevice->FtwWorkSpace,\r
398 Ptr,\r
399 FtwLiteDevice->FtwWorkSpaceSize\r
400 );\r
401\r
402 Status = FtwGetLastRecord (FtwLiteDevice, &FtwLiteDevice->FtwLastRecord);\r
403\r
404 //\r
405 // Set the WorkingBlockValid and WorkingBlockInvalid as INVALID\r
406 //\r
407 WorkingBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) Ptr;\r
408 WorkingBlockHeader->WorkingBlockValid = FTW_INVALID_STATE;\r
409 WorkingBlockHeader->WorkingBlockInvalid = FTW_INVALID_STATE;\r
410\r
411 //\r
412 // Try to keep the content of spare block\r
413 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
414 //\r
415 SpareBufferSize = FtwLiteDevice->SpareAreaLength;\r
416 SpareBuffer = AllocatePool (SpareBufferSize);\r
417 if (SpareBuffer == NULL) {\r
418 FreePool (TempBuffer);\r
419 return EFI_OUT_OF_RESOURCES;\r
420 }\r
421\r
422 Ptr = SpareBuffer;\r
423 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
424 Length = FtwLiteDevice->SizeOfSpareBlock;\r
425 Status = FtwLiteDevice->FtwBackupFvb->Read (\r
426 FtwLiteDevice->FtwBackupFvb,\r
427 FtwLiteDevice->FtwSpareLba + Index,\r
428 0,\r
429 &Length,\r
430 Ptr\r
431 );\r
432 if (EFI_ERROR (Status)) {\r
433 FreePool (TempBuffer);\r
434 FreePool (SpareBuffer);\r
435 return EFI_ABORTED;\r
436 }\r
437\r
438 Ptr += Length;\r
439 }\r
440 //\r
441 // Write the memory buffer to spare block\r
442 //\r
443 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
444 Ptr = TempBuffer;\r
445 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
446 Length = FtwLiteDevice->SizeOfSpareBlock;\r
447 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
448 FtwLiteDevice->FtwBackupFvb,\r
449 FtwLiteDevice->FtwSpareLba + Index,\r
450 0,\r
451 &Length,\r
452 Ptr\r
453 );\r
454 if (EFI_ERROR (Status)) {\r
455 FreePool (TempBuffer);\r
456 FreePool (SpareBuffer);\r
457 return EFI_ABORTED;\r
458 }\r
459\r
460 Ptr += Length;\r
461 }\r
462 //\r
463 // Free TempBuffer\r
464 //\r
465 FreePool (TempBuffer);\r
466\r
467 //\r
468 // Write the spare block to working block\r
469 //\r
470 Status = FlushSpareBlockToWorkingBlock (FtwLiteDevice);\r
471 if (EFI_ERROR (Status)) {\r
472 FreePool (SpareBuffer);\r
473 return Status;\r
474 }\r
475 //\r
476 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
477 //\r
478 Status = FtwEraseSpareBlock (FtwLiteDevice);\r
479 Ptr = SpareBuffer;\r
480 for (Index = 0; Index < FtwLiteDevice->NumberOfSpareBlock; Index += 1) {\r
481 Length = FtwLiteDevice->SizeOfSpareBlock;\r
482 Status = FtwLiteDevice->FtwBackupFvb->Write (\r
483 FtwLiteDevice->FtwBackupFvb,\r
484 FtwLiteDevice->FtwSpareLba + Index,\r
485 0,\r
486 &Length,\r
487 Ptr\r
488 );\r
489 if (EFI_ERROR (Status)) {\r
490 FreePool (SpareBuffer);\r
491 return EFI_ABORTED;\r
492 }\r
493\r
494 Ptr += Length;\r
495 }\r
496\r
497 FreePool (SpareBuffer);\r
498\r
499 DEBUG ((EFI_D_FTW_LITE, "FtwLite: reclaim work space success\n"));\r
500\r
501 return EFI_SUCCESS;\r
502}\r