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