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