]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
Retire TCG platform protocol, which will be replaced by PI Security Architecture...
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWrite.c
CommitLineData
85e923a5
LG
1/** @file\r
2\r
3 This is a simple fault tolerant write driver.\r
4\r
5 This boot service protocol only provides fault tolerant write capability for \r
6 block devices. The protocol has internal non-volatile intermediate storage \r
7 of the data and private information. It should be able to recover \r
8 automatically from a critical fault, such as power failure. \r
9\r
10 The implementation uses an FTW (Fault Tolerant Write) Work Space. \r
11 This work space is a memory copy of the work space on the Working Block,\r
12 the size of the work space is the FTW_WORK_SPACE_SIZE bytes.\r
13 \r
14 The work space stores each write record as EFI_FTW_RECORD structure.\r
15 The spare block stores the write buffer before write to the target block.\r
16 \r
17 The write record has three states to specify the different phase of write operation.\r
18 1) WRITE_ALLOCATED is that the record is allocated in write space.\r
19 The information of write operation is stored in write record structure.\r
20 2) SPARE_COMPLETED is that the data from write buffer is writed into the spare block as the backup.\r
21 3) WRITE_COMPLETED is that the data is copied from the spare block to the target block.\r
22\r
23 This driver operates the data as the whole size of spare block.\r
24 It first read the SpareAreaLength data from the target block into the spare memory buffer.\r
25 Then copy the write buffer data into the spare memory buffer.\r
26 Then write the spare memory buffer into the spare block.\r
27 Final copy the data from the spare block to the target block.\r
28\r
29 To make this drive work well, the following conditions must be satisfied:\r
30 1. The write NumBytes data must be fit within Spare area. \r
31 Offset + NumBytes <= SpareAreaLength\r
32 2. The whole flash range has the same block size.\r
33 3. Working block is an area which contains working space in its last block and has the same size as spare block.\r
34 4. Working Block area must be in the single one Firmware Volume Block range which FVB protocol is produced on. \r
35 5. Spare area must be in the single one Firmware Volume Block range which FVB protocol is produced on.\r
36 6. Any write data area (SpareAreaLength Area) which the data will be written into must be \r
37 in the single one Firmware Volume Block range which FVB protocol is produced on.\r
38 7. If write data area (such as Variable range) is enlarged, the spare area range must be enlarged.\r
39 The spare area must be enough large to store the write data before write them into the target range.\r
40 If one of them is not satisfied, FtwWrite may fail.\r
41 Usually, Spare area only takes one block. That's SpareAreaLength = BlockSize, NumberOfSpareBlock = 1.\r
42\r
43Copyright (c) 2006 - 2009, Intel Corporation \r
44All rights reserved. This program and the accompanying materials \r
45are licensed and made available under the terms and conditions of the BSD License \r
46which accompanies this distribution. The full text of the license may be found at \r
47http://opensource.org/licenses/bsd-license.php \r
48 \r
49THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
50WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
51\r
52**/\r
53\r
54#include "FaultTolerantWrite.h"\r
55\r
56\r
57//\r
58// Fault Tolerant Write Protocol API\r
59//\r
60/**\r
61 Query the largest block that may be updated in a fault tolerant manner.\r
62\r
63\r
64 @param This The pointer to this protocol instance. \r
65 @param BlockSize A pointer to a caller allocated UINTN that is updated to\r
66 indicate the size of the largest block that can be updated.\r
67\r
68 @return EFI_SUCCESS The function completed successfully\r
69\r
70**/\r
71EFI_STATUS\r
72EFIAPI\r
73FtwGetMaxBlockSize (\r
74 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
75 OUT UINTN *BlockSize\r
76 )\r
77{\r
78 EFI_FTW_DEVICE *FtwDevice;\r
79\r
80 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
81 return EFI_UNSUPPORTED;\r
82 }\r
83\r
84 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
85\r
86 *BlockSize = FtwDevice->SpareAreaLength;\r
87\r
88 return EFI_SUCCESS;\r
89}\r
90\r
91/**\r
92 Allocates space for the protocol to maintain information about writes.\r
93 Since writes must be completed in a fault tolerant manner and multiple\r
94 updates will require more resources to be successful, this function\r
95 enables the protocol to ensure that enough space exists to track\r
96 information about the upcoming writes.\r
97\r
98 All writes must be completed or aborted before another fault tolerant write can occur.\r
99\r
100 @param This The pointer to this protocol instance. \r
101 @param CallerId The GUID identifying the write.\r
102 @param PrivateDataSize The size of the caller's private data\r
103 that must be recorded for each write.\r
104 @param NumberOfWrites The number of fault tolerant block writes\r
105 that will need to occur.\r
106\r
107 @return EFI_SUCCESS The function completed successfully\r
108 @retval EFI_ABORTED The function could not complete successfully.\r
109 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.\r
110\r
111**/\r
112EFI_STATUS\r
113EFIAPI\r
114FtwAllocate (\r
115 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
116 IN EFI_GUID *CallerId,\r
117 IN UINTN PrivateDataSize,\r
118 IN UINTN NumberOfWrites\r
119 )\r
120{\r
121 EFI_STATUS Status;\r
122 UINTN Length;\r
123 UINTN Offset;\r
124 EFI_FTW_DEVICE *FtwDevice;\r
125 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
126\r
127 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
128\r
129 Status = WorkSpaceRefresh (FtwDevice);\r
130 if (EFI_ERROR (Status)) {\r
131 return EFI_ABORTED;\r
132 }\r
133 //\r
134 // Check if there is enough space for the coming allocation\r
135 //\r
136 if (WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {\r
137 DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));\r
138 return EFI_BUFFER_TOO_SMALL;\r
139 }\r
140 //\r
141 // Find the last write header and record.\r
142 // If the FtwHeader is complete, skip the completed last write header/records\r
143 //\r
144 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
145\r
146 //\r
147 // Previous write has not completed, access denied.\r
148 //\r
149 if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {\r
150 return EFI_ACCESS_DENIED;\r
151 }\r
152 //\r
153 // If workspace is not enough, then reclaim workspace\r
154 //\r
155 Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;\r
156 if (Offset + WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {\r
157 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
158 if (EFI_ERROR (Status)) {\r
159 return EFI_ABORTED;\r
160 }\r
161\r
162 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
163 }\r
164 //\r
165 // Prepare FTW write header,\r
166 // overwrite the buffer and write to workspace.\r
167 //\r
168 FtwHeader->WritesAllocated = FTW_INVALID_STATE;\r
169 FtwHeader->Complete = FTW_INVALID_STATE;\r
170 CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));\r
171 FtwHeader->NumberOfWrites = NumberOfWrites;\r
172 FtwHeader->PrivateDataSize = PrivateDataSize;\r
173 FtwHeader->HeaderAllocated = FTW_VALID_STATE;\r
174\r
175 Length = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);\r
176 Status = FtwDevice->FtwFvBlock->Write (\r
177 FtwDevice->FtwFvBlock,\r
178 FtwDevice->FtwWorkSpaceLba,\r
179 FtwDevice->FtwWorkSpaceBase + Offset,\r
180 &Length,\r
181 (UINT8 *) FtwHeader\r
182 );\r
183 if (EFI_ERROR (Status)) {\r
184 return EFI_ABORTED;\r
185 }\r
186 //\r
187 // Update Header->WriteAllocated as VALID\r
188 //\r
189 Status = FtwUpdateFvState (\r
190 FtwDevice->FtwFvBlock,\r
191 FtwDevice->FtwWorkSpaceLba,\r
192 FtwDevice->FtwWorkSpaceBase + Offset,\r
193 WRITES_ALLOCATED\r
194 );\r
195 if (EFI_ERROR (Status)) {\r
196 return EFI_ABORTED;\r
197 }\r
198\r
199 DEBUG (\r
200 (EFI_D_ERROR,\r
201 "Ftw: Allocate() success, Caller:%g, # %d\n",\r
202 CallerId,\r
203 NumberOfWrites)\r
204 );\r
205\r
206 return EFI_SUCCESS;\r
207}\r
208\r
209\r
210/**\r
211 Write a record with fault tolerant mannaer.\r
212 Since the content has already backuped in spare block, the write is\r
213 guaranteed to be completed with fault tolerant manner.\r
214\r
215 @param This The pointer to this protocol instance. \r
216 @param Fvb The FVB protocol that provides services for\r
217 reading, writing, and erasing the target block.\r
218\r
219 @retval EFI_SUCCESS The function completed successfully\r
220 @retval EFI_ABORTED The function could not complete successfully\r
221\r
222**/\r
223EFI_STATUS\r
224FtwWriteRecord (\r
225 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
226 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb\r
227 )\r
228{\r
229 EFI_STATUS Status;\r
230 EFI_FTW_DEVICE *FtwDevice;\r
231 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
232 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
233 UINTN Offset;\r
234\r
235 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
236\r
237 //\r
238 // Spare Complete but Destination not complete,\r
239 // Recover the targt block with the spare block.\r
240 //\r
241 Header = FtwDevice->FtwLastWriteHeader;\r
242 Record = FtwDevice->FtwLastWriteRecord;\r
243\r
244 //\r
245 // IF target block is working block, THEN Flush Spare Block To Working Block;\r
246 // ELSE flush spare block to target block, which may be boot block after all.\r
247 //\r
248 if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {\r
249 //\r
250 // If target block is working block,\r
251 // it also need to set SPARE_COMPLETED to spare block.\r
252 //\r
253 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
254 Status = FtwUpdateFvState (\r
255 FtwDevice->FtwBackupFvb,\r
256 FtwDevice->FtwWorkSpaceLba,\r
257 FtwDevice->FtwWorkSpaceBase + Offset,\r
258 SPARE_COMPLETED\r
259 );\r
260 if (EFI_ERROR (Status)) {\r
261 return EFI_ABORTED;\r
262 }\r
263\r
264 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
265 } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {\r
266 //\r
267 // Update boot block\r
268 //\r
269 Status = FlushSpareBlockToBootBlock (FtwDevice);\r
270 } else {\r
271 //\r
272 // Update blocks other than working block or boot block\r
273 //\r
274 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);\r
275 }\r
276\r
277 if (EFI_ERROR (Status)) {\r
278 return EFI_ABORTED;\r
279 }\r
280 //\r
281 // Record the DestionationComplete in record\r
282 //\r
283 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
284 Status = FtwUpdateFvState (\r
285 FtwDevice->FtwFvBlock,\r
286 FtwDevice->FtwWorkSpaceLba,\r
287 FtwDevice->FtwWorkSpaceBase + Offset,\r
288 DEST_COMPLETED\r
289 );\r
290 if (EFI_ERROR (Status)) {\r
291 return EFI_ABORTED;\r
292 }\r
293\r
294 Record->DestinationComplete = FTW_VALID_STATE;\r
295\r
296 //\r
297 // If this is the last Write in these write sequence,\r
298 // set the complete flag of write header.\r
299 //\r
300 if (IsLastRecordOfWrites (Header, Record)) {\r
301 Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;\r
302 Status = FtwUpdateFvState (\r
303 FtwDevice->FtwFvBlock,\r
304 FtwDevice->FtwWorkSpaceLba,\r
305 FtwDevice->FtwWorkSpaceBase + Offset,\r
306 WRITES_COMPLETED\r
307 );\r
308 Header->Complete = FTW_VALID_STATE;\r
309 if (EFI_ERROR (Status)) {\r
310 return EFI_ABORTED;\r
311 }\r
312 }\r
313\r
314 return EFI_SUCCESS;\r
315}\r
316\r
317/**\r
318 Starts a target block update. This function will record data about write\r
319 in fault tolerant storage and will complete the write in a recoverable\r
320 manner, ensuring at all times that either the original contents or\r
321 the modified contents are available.\r
322\r
323 @param This The pointer to this protocol instance. \r
324 @param Lba The logical block address of the target block.\r
325 @param Offset The offset within the target block to place the data.\r
326 @param Length The number of bytes to write to the target block.\r
327 @param PrivateData A pointer to private data that the caller requires to\r
328 complete any pending writes in the event of a fault.\r
329 @param FvBlockHandle The handle of FVB protocol that provides services for\r
330 reading, writing, and erasing the target block.\r
331 @param Buffer The data to write.\r
332\r
333 @retval EFI_SUCCESS The function completed successfully \r
334 @retval EFI_ABORTED The function could not complete successfully. \r
335 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block. \r
336 Offset + *NumBytes > SpareAreaLength.\r
337 @retval EFI_ACCESS_DENIED No writes have been allocated. \r
338 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.\r
339 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.\r
340\r
341**/\r
342EFI_STATUS\r
343EFIAPI\r
344FtwWrite (\r
345 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
346 IN EFI_LBA Lba,\r
347 IN UINTN Offset,\r
348 IN UINTN Length,\r
349 IN VOID *PrivateData,\r
350 IN EFI_HANDLE FvBlockHandle,\r
351 IN VOID *Buffer\r
352 )\r
353{\r
354 EFI_STATUS Status;\r
355 EFI_FTW_DEVICE *FtwDevice;\r
356 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
357 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
358 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
359 UINTN MyLength;\r
360 UINTN MyOffset;\r
361 UINTN MyBufferSize;\r
362 UINT8 *MyBuffer;\r
363 UINTN SpareBufferSize;\r
364 UINT8 *SpareBuffer;\r
365 UINTN Index;\r
366 UINT8 *Ptr;\r
367 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;\r
368\r
369 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
370\r
371 Status = WorkSpaceRefresh (FtwDevice);\r
372 if (EFI_ERROR (Status)) {\r
373 return EFI_ABORTED;\r
374 }\r
375\r
376 Header = FtwDevice->FtwLastWriteHeader;\r
377 Record = FtwDevice->FtwLastWriteRecord;\r
378 \r
379 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {\r
380 if (PrivateData == NULL) {\r
381 //\r
382 // Ftw Write Header is not allocated.\r
383 // No additional private data, the private data size is zero. Number of record can be set to 1.\r
384 //\r
385 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);\r
386 if (EFI_ERROR (Status)) {\r
387 return Status;\r
388 }\r
389 } else {\r
390 //\r
391 // Ftw Write Header is not allocated\r
392 // Additional private data is not NULL, the private data size can't be determined.\r
393 //\r
394 DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));\r
395 DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));\r
396 return EFI_NOT_READY;\r
397 }\r
398 }\r
399\r
400 //\r
401 // If Record is out of the range of Header, return access denied.\r
402 //\r
403 if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {\r
404 return EFI_ACCESS_DENIED;\r
405 }\r
406\r
407 //\r
408 // Check the COMPLETE flag of last write header\r
409 //\r
410 if (Header->Complete == FTW_VALID_STATE) {\r
411 return EFI_ACCESS_DENIED;\r
412 }\r
413\r
414 if (Record->DestinationComplete == FTW_VALID_STATE) {\r
415 return EFI_ACCESS_DENIED;\r
416 }\r
417\r
418 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {\r
419 return EFI_NOT_READY;\r
420 }\r
421 //\r
422 // Check if the input data can fit within the target block\r
423 //\r
424 if ((Offset + Length) > FtwDevice->SpareAreaLength) {\r
425 return EFI_BAD_BUFFER_SIZE;\r
426 }\r
427 //\r
428 // Get the FVB protocol by handle\r
429 //\r
430 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);\r
431 if (EFI_ERROR (Status)) {\r
432 return EFI_NOT_FOUND;\r
433 }\r
434\r
435 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);\r
436 if (EFI_ERROR (Status)) {\r
437 DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));\r
438 return EFI_ABORTED;\r
439 }\r
440\r
441 //\r
442 // Set BootBlockUpdate FLAG if it's updating boot block.\r
443 //\r
444 if (IsBootBlock (FtwDevice, Fvb, Lba)) {\r
445 Record->BootBlockUpdate = FTW_VALID_STATE;\r
446 }\r
447 //\r
448 // Write the record to the work space.\r
449 //\r
450 Record->Lba = Lba;\r
451 Record->Offset = Offset;\r
452 Record->Length = Length;\r
453 Record->FvBaseAddress = FvbPhysicalAddress;\r
454 CopyMem ((Record + 1), PrivateData, Header->PrivateDataSize);\r
455\r
456 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
457 MyLength = RECORD_SIZE (Header->PrivateDataSize);\r
458\r
459 Status = FtwDevice->FtwFvBlock->Write (\r
460 FtwDevice->FtwFvBlock,\r
461 FtwDevice->FtwWorkSpaceLba,\r
462 FtwDevice->FtwWorkSpaceBase + MyOffset,\r
463 &MyLength,\r
464 (UINT8 *) Record\r
465 );\r
466 if (EFI_ERROR (Status)) {\r
467 return EFI_ABORTED;\r
468 }\r
469 //\r
470 // Record has written to working block, then do the data.\r
471 //\r
472 //\r
473 // Allocate a memory buffer\r
474 //\r
475 MyBufferSize = FtwDevice->SpareAreaLength;\r
476 MyBuffer = AllocatePool (MyBufferSize);\r
477 if (MyBuffer == NULL) {\r
478 return EFI_OUT_OF_RESOURCES;\r
479 }\r
480 //\r
481 // Read all original data from target block to memory buffer\r
482 //\r
483 Ptr = MyBuffer;\r
484 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
485 MyLength = FtwDevice->BlockSize;\r
486 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);\r
487 if (EFI_ERROR (Status)) {\r
488 FreePool (MyBuffer);\r
489 return EFI_ABORTED;\r
490 }\r
491\r
492 Ptr += MyLength;\r
493 }\r
494 //\r
495 // Overwrite the updating range data with\r
496 // the input buffer content\r
497 //\r
498 CopyMem (MyBuffer + Offset, Buffer, Length);\r
499\r
500 //\r
501 // Try to keep the content of spare block\r
502 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
503 //\r
504 SpareBufferSize = FtwDevice->SpareAreaLength;\r
505 SpareBuffer = AllocatePool (SpareBufferSize);\r
506 if (SpareBuffer == NULL) {\r
507 FreePool (MyBuffer);\r
508 return EFI_OUT_OF_RESOURCES;\r
509 }\r
510\r
511 Ptr = SpareBuffer;\r
512 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
513 MyLength = FtwDevice->BlockSize;\r
514 Status = FtwDevice->FtwBackupFvb->Read (\r
515 FtwDevice->FtwBackupFvb,\r
516 FtwDevice->FtwSpareLba + Index,\r
517 0,\r
518 &MyLength,\r
519 Ptr\r
520 );\r
521 if (EFI_ERROR (Status)) {\r
522 FreePool (MyBuffer);\r
523 FreePool (SpareBuffer);\r
524 return EFI_ABORTED;\r
525 }\r
526\r
527 Ptr += MyLength;\r
528 }\r
529 //\r
530 // Write the memory buffer to spare block\r
531 //\r
532 Status = FtwEraseSpareBlock (FtwDevice);\r
533 Ptr = MyBuffer;\r
534 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
535 MyLength = FtwDevice->BlockSize;\r
536 Status = FtwDevice->FtwBackupFvb->Write (\r
537 FtwDevice->FtwBackupFvb,\r
538 FtwDevice->FtwSpareLba + Index,\r
539 0,\r
540 &MyLength,\r
541 Ptr\r
542 );\r
543 if (EFI_ERROR (Status)) {\r
544 FreePool (MyBuffer);\r
545 FreePool (SpareBuffer);\r
546 return EFI_ABORTED;\r
547 }\r
548\r
549 Ptr += MyLength;\r
550 }\r
551 //\r
552 // Free MyBuffer\r
553 //\r
554 FreePool (MyBuffer);\r
555\r
556 //\r
557 // Set the SpareComplete in the FTW record,\r
558 //\r
559 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
560 Status = FtwUpdateFvState (\r
561 FtwDevice->FtwFvBlock,\r
562 FtwDevice->FtwWorkSpaceLba,\r
563 FtwDevice->FtwWorkSpaceBase + MyOffset,\r
564 SPARE_COMPLETED\r
565 );\r
566 if (EFI_ERROR (Status)) {\r
567 FreePool (SpareBuffer);\r
568 return EFI_ABORTED;\r
569 }\r
570\r
571 Record->SpareComplete = FTW_VALID_STATE;\r
572\r
573 //\r
574 // Since the content has already backuped in spare block, the write is\r
575 // guaranteed to be completed with fault tolerant manner.\r
576 //\r
577 Status = FtwWriteRecord (This, Fvb);\r
578 if (EFI_ERROR (Status)) {\r
579 FreePool (SpareBuffer);\r
580 return EFI_ABORTED;\r
581 }\r
582 //\r
583 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
584 //\r
585 Status = FtwEraseSpareBlock (FtwDevice);\r
586 Ptr = SpareBuffer;\r
587 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
588 MyLength = FtwDevice->BlockSize;\r
589 Status = FtwDevice->FtwBackupFvb->Write (\r
590 FtwDevice->FtwBackupFvb,\r
591 FtwDevice->FtwSpareLba + Index,\r
592 0,\r
593 &MyLength,\r
594 Ptr\r
595 );\r
596 if (EFI_ERROR (Status)) {\r
597 FreePool (SpareBuffer);\r
598 return EFI_ABORTED;\r
599 }\r
600\r
601 Ptr += MyLength;\r
602 }\r
603 //\r
604 // All success.\r
605 //\r
606 FreePool (SpareBuffer);\r
607\r
608 DEBUG (\r
609 (EFI_D_ERROR,\r
610 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",\r
611 Lba,\r
612 Offset,\r
613 Length)\r
614 );\r
615\r
616 return EFI_SUCCESS;\r
617}\r
618\r
619/**\r
620 Restarts a previously interrupted write. The caller must provide the\r
621 block protocol needed to complete the interrupted write.\r
622\r
623 @param This The pointer to this protocol instance. \r
624 @param FvBlockHandle The handle of FVB protocol that provides services for\r
625 reading, writing, and erasing the target block.\r
626\r
627 @retval EFI_SUCCESS The function completed successfully\r
628 @retval EFI_ACCESS_DENIED No pending writes exist\r
629 @retval EFI_NOT_FOUND FVB protocol not found by the handle\r
630 @retval EFI_ABORTED The function could not complete successfully\r
631\r
632**/\r
633EFI_STATUS\r
634EFIAPI\r
635FtwRestart (\r
636 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
637 IN EFI_HANDLE FvBlockHandle\r
638 )\r
639{\r
640 EFI_STATUS Status;\r
641 EFI_FTW_DEVICE *FtwDevice;\r
642 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
643 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
644 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
645\r
646 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
647\r
648 Status = WorkSpaceRefresh (FtwDevice);\r
649 if (EFI_ERROR (Status)) {\r
650 return EFI_ABORTED;\r
651 }\r
652\r
653 Header = FtwDevice->FtwLastWriteHeader;\r
654 Record = FtwDevice->FtwLastWriteRecord;\r
655\r
656 //\r
657 // Spare Complete but Destination not complete,\r
658 // Recover the targt block with the spare block.\r
659 //\r
660 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);\r
661 if (EFI_ERROR (Status)) {\r
662 return EFI_NOT_FOUND;\r
663 }\r
664\r
665 //\r
666 // Check the COMPLETE flag of last write header\r
667 //\r
668 if (Header->Complete == FTW_VALID_STATE) {\r
669 return EFI_ACCESS_DENIED;\r
670 }\r
671\r
672 //\r
673 // Check the flags of last write record\r
674 //\r
675 if (Record->DestinationComplete == FTW_VALID_STATE) {\r
676 return EFI_ACCESS_DENIED;\r
677 }\r
678\r
679 if ((Record->SpareComplete != FTW_VALID_STATE)) {\r
680 return EFI_ABORTED;\r
681 }\r
682\r
683 //\r
684 // Since the content has already backuped in spare block, the write is\r
685 // guaranteed to be completed with fault tolerant manner.\r
686 //\r
687 Status = FtwWriteRecord (This, Fvb);\r
688 if (EFI_ERROR (Status)) {\r
689 return EFI_ABORTED;\r
690 }\r
691\r
692 //\r
693 // Erase Spare block\r
694 // This is restart, no need to keep spareblock content.\r
695 //\r
696 FtwEraseSpareBlock (FtwDevice);\r
697\r
698 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));\r
699 return EFI_SUCCESS;\r
700}\r
701\r
702/**\r
703 Aborts all previous allocated writes.\r
704\r
705 @param This The pointer to this protocol instance. \r
706\r
707 @retval EFI_SUCCESS The function completed successfully\r
708 @retval EFI_ABORTED The function could not complete successfully.\r
709 @retval EFI_NOT_FOUND No allocated writes exist.\r
710\r
711**/\r
712EFI_STATUS\r
713EFIAPI\r
714FtwAbort (\r
715 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This\r
716 )\r
717{\r
718 EFI_STATUS Status;\r
719 UINTN Offset;\r
720 EFI_FTW_DEVICE *FtwDevice;\r
721\r
722 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
723\r
724 Status = WorkSpaceRefresh (FtwDevice);\r
725 if (EFI_ERROR (Status)) {\r
726 return EFI_ABORTED;\r
727 }\r
728\r
729 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {\r
730 return EFI_NOT_FOUND;\r
731 }\r
732 //\r
733 // Update the complete state of the header as VALID and abort.\r
734 //\r
735 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;\r
736 Status = FtwUpdateFvState (\r
737 FtwDevice->FtwFvBlock,\r
738 FtwDevice->FtwWorkSpaceLba,\r
739 FtwDevice->FtwWorkSpaceBase + Offset,\r
740 WRITES_COMPLETED\r
741 );\r
742 if (EFI_ERROR (Status)) {\r
743 return EFI_ABORTED;\r
744 }\r
745\r
746 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;\r
747\r
748 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));\r
749 return EFI_SUCCESS;\r
750}\r
751\r
752/**\r
753 Starts a target block update. This records information about the write\r
754 in fault tolerant storage and will complete the write in a recoverable\r
755 manner, ensuring at all times that either the original contents or\r
756 the modified contents are available.\r
757\r
758 @param This The pointer to this protocol instance. \r
759 @param CallerId The GUID identifying the last write.\r
760 @param Lba The logical block address of the last write.\r
761 @param Offset The offset within the block of the last write.\r
762 @param Length The length of the last write.\r
763 @param PrivateDataSize bytes from the private data\r
764 stored for this write.\r
765 @param PrivateData A pointer to a buffer. The function will copy\r
766 @param Complete A Boolean value with TRUE indicating\r
767 that the write was completed.\r
768\r
769 @retval EFI_SUCCESS The function completed successfully\r
770 @retval EFI_ABORTED The function could not complete successfully\r
771 @retval EFI_NOT_FOUND No allocated writes exist\r
772 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough\r
773\r
774**/\r
775EFI_STATUS\r
776EFIAPI\r
777FtwGetLastWrite (\r
778 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
779 OUT EFI_GUID *CallerId,\r
780 OUT EFI_LBA *Lba,\r
781 OUT UINTN *Offset,\r
782 OUT UINTN *Length,\r
783 IN OUT UINTN *PrivateDataSize,\r
784 OUT VOID *PrivateData,\r
785 OUT BOOLEAN *Complete\r
786 )\r
787{\r
788 EFI_STATUS Status;\r
789 EFI_FTW_DEVICE *FtwDevice;\r
790 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
791 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
792\r
793 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
794 return EFI_UNSUPPORTED;\r
795 }\r
796\r
797 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
798\r
799 Status = WorkSpaceRefresh (FtwDevice);\r
800 if (EFI_ERROR (Status)) {\r
801 return EFI_ABORTED;\r
802 }\r
803\r
804 Header = FtwDevice->FtwLastWriteHeader;\r
805 Record = FtwDevice->FtwLastWriteRecord;\r
806\r
807 //\r
808 // If Header is incompleted and the last record has completed, then\r
809 // call Abort() to set the Header->Complete FLAG.\r
810 //\r
811 if ((Header->Complete != FTW_VALID_STATE) &&\r
812 (Record->DestinationComplete == FTW_VALID_STATE) &&\r
813 IsLastRecordOfWrites (Header, Record)\r
814 ) {\r
815\r
816 Status = FtwAbort (This);\r
817 *Complete = TRUE;\r
818 return EFI_NOT_FOUND;\r
819 }\r
820 //\r
821 // If there is no write header/record, return not found.\r
822 //\r
823 if (Header->HeaderAllocated != FTW_VALID_STATE) {\r
824 *Complete = TRUE;\r
825 return EFI_NOT_FOUND;\r
826 }\r
827 //\r
828 // If this record SpareComplete has not set, then it can not restart.\r
829 //\r
830 if (Record->SpareComplete != FTW_VALID_STATE) {\r
831 if (IsFirstRecordOfWrites (Header, Record)) {\r
832 //\r
833 // The First record cannot be restart and target is still healthy,\r
834 // so abort() is a safe solution.\r
835 //\r
836 FtwAbort (This);\r
837\r
838 *Complete = TRUE;\r
839 return EFI_NOT_FOUND;\r
840 } else {\r
841 //\r
842 // Step back to the previous record\r
843 //\r
844 GetPreviousRecordOfWrites (Header, &Record);\r
845 }\r
846 }\r
847 //\r
848 // Fill all the requested values\r
849 //\r
850 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));\r
851 *Lba = Record->Lba;\r
852 *Offset = Record->Offset;\r
853 *Length = Record->Length;\r
854 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);\r
855\r
856 if (*PrivateDataSize < Header->PrivateDataSize) {\r
857 *PrivateDataSize = Header->PrivateDataSize;\r
858 PrivateData = NULL;\r
859 Status = EFI_BUFFER_TOO_SMALL;\r
860 } else {\r
861 *PrivateDataSize = Header->PrivateDataSize;\r
862 CopyMem (PrivateData, Record + 1, *PrivateDataSize);\r
863 Status = EFI_SUCCESS;\r
864 }\r
865\r
866 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));\r
867\r
868 return Status;\r
869}\r
870\r
871/**\r
872 This function is the entry point of the Fault Tolerant Write driver.\r
873\r
874 @param ImageHandle A handle for the image that is initializing this driver\r
875 @param SystemTable A pointer to the EFI system table\r
876\r
877 @return EFI_SUCCESS FTW has finished the initialization\r
878 @retval EFI_NOT_FOUND Locate FVB protocol error\r
879 @retval EFI_OUT_OF_RESOURCES Allocate memory error\r
880 @retval EFI_VOLUME_CORRUPTED Firmware volume is error\r
881 @retval EFI_ABORTED FTW initialization error\r
882\r
883**/\r
884EFI_STATUS\r
885EFIAPI\r
886InitializeFaultTolerantWrite (\r
887 IN EFI_HANDLE ImageHandle,\r
888 IN EFI_SYSTEM_TABLE *SystemTable\r
889 )\r
890{\r
891 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
892 UINTN Index;\r
893 EFI_HANDLE *HandleBuffer;\r
894 UINTN HandleCount;\r
895 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
896 EFI_PHYSICAL_ADDRESS BaseAddress;\r
897 EFI_FTW_DEVICE *FtwDevice;\r
898 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
899 UINTN Length;\r
900 EFI_STATUS Status;\r
901 UINTN Offset;\r
902 EFI_FV_BLOCK_MAP_ENTRY *FvbMapEntry;\r
903 UINT32 LbaIndex;\r
904 EFI_HANDLE FvbHandle;\r
905\r
906 //\r
907 // Allocate Private data of this driver,\r
908 // INCLUDING THE FtwWorkSpace[FTW_WORK_SPACE_SIZE].\r
909 //\r
910 FvbHandle = NULL;\r
911 FtwDevice = NULL;\r
912 FtwDevice = AllocatePool (sizeof (EFI_FTW_DEVICE) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize));\r
913 if (FtwDevice == NULL) {\r
914 return EFI_OUT_OF_RESOURCES;\r
915 }\r
916\r
917 ZeroMem (FtwDevice, sizeof (EFI_FTW_DEVICE));\r
918 FtwDevice->Signature = FTW_DEVICE_SIGNATURE;\r
919\r
920 //\r
921 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
922 //\r
923\r
924 FtwDevice->WorkSpaceAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwWorkingBase);\r
925 FtwDevice->WorkSpaceLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwWorkingSize);\r
926\r
927 FtwDevice->SpareAreaAddress = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageFtwSpareBase);\r
928 FtwDevice->SpareAreaLength = (UINTN) PcdGet32 (PcdFlashNvStorageFtwSpareSize);\r
929\r
930 if ((FtwDevice->WorkSpaceLength == 0) || (FtwDevice->SpareAreaLength == 0)) {\r
931 DEBUG ((EFI_D_ERROR, "Ftw: Workspace or Spare block does not exist!\n"));\r
932 FreePool (FtwDevice);\r
933 return EFI_OUT_OF_RESOURCES;\r
934 }\r
935 //\r
936 // Locate FVB protocol by handle\r
937 //\r
938 Status = gBS->LocateHandleBuffer (\r
939 ByProtocol,\r
940 &gEfiFirmwareVolumeBlockProtocolGuid,\r
941 NULL,\r
942 &HandleCount,\r
943 &HandleBuffer\r
944 );\r
945 if (EFI_ERROR (Status)) {\r
946 FreePool (FtwDevice);\r
947 return EFI_NOT_FOUND;\r
948 }\r
949\r
950 if (HandleCount <= 0) {\r
951 FreePool (FtwDevice);\r
952 return EFI_NOT_FOUND;\r
953 }\r
954\r
955 Fvb = NULL;\r
956 FtwDevice->FtwFvBlock = NULL;\r
957 FtwDevice->FtwBackupFvb = NULL;\r
958 FtwDevice->FtwWorkSpaceLba = (EFI_LBA) (-1);\r
959 FtwDevice->FtwSpareLba = (EFI_LBA) (-1);\r
960 for (Index = 0; Index < HandleCount; Index += 1) {\r
961 Status = gBS->HandleProtocol (\r
962 HandleBuffer[Index],\r
963 &gEfiFirmwareVolumeBlockProtocolGuid,\r
964 (VOID **) &Fvb\r
965 );\r
966 if (EFI_ERROR (Status)) {\r
967 FreePool (FtwDevice);\r
968 return Status;\r
969 }\r
970\r
971 Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);\r
972 if (EFI_ERROR (Status)) {\r
973 continue;\r
974 }\r
975\r
976 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) BaseAddress);\r
977\r
978 if ((FtwDevice->WorkSpaceAddress >= BaseAddress) &&\r
979 ((FtwDevice->WorkSpaceAddress + FtwDevice->WorkSpaceLength) <= (BaseAddress + FwVolHeader->FvLength))\r
980 ) {\r
981 FtwDevice->FtwFvBlock = Fvb;\r
982 //\r
983 // To get the LBA of work space\r
984 //\r
985 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
986 //\r
987 // Now, one FV has one type of BlockLength\r
988 //\r
989 FvbMapEntry = &FwVolHeader->BlockMap[0];\r
990 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
991 if ((FtwDevice->WorkSpaceAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
992 && (FtwDevice->WorkSpaceAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
993 FtwDevice->FtwWorkSpaceLba = LbaIndex - 1;\r
994 //\r
995 // Get the Work space size and Base(Offset)\r
996 //\r
997 FtwDevice->FtwWorkSpaceSize = FtwDevice->WorkSpaceLength;\r
998 FtwDevice->FtwWorkSpaceBase = (UINTN) (FtwDevice->WorkSpaceAddress - (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)));\r
999 break;\r
1000 }\r
1001 }\r
1002 }\r
1003 }\r
1004\r
1005 if ((FtwDevice->SpareAreaAddress >= BaseAddress) &&\r
1006 ((FtwDevice->SpareAreaAddress + FtwDevice->SpareAreaLength) <= (BaseAddress + FwVolHeader->FvLength))\r
1007 ) {\r
1008 FtwDevice->FtwBackupFvb = Fvb;\r
1009 //\r
1010 // To get the LBA of spare\r
1011 //\r
1012 if ((FwVolHeader->FvLength) > (FwVolHeader->HeaderLength)) {\r
1013 //\r
1014 // Now, one FV has one type of BlockLength\r
1015 //\r
1016 FvbMapEntry = &FwVolHeader->BlockMap[0];\r
1017 for (LbaIndex = 1; LbaIndex <= FvbMapEntry->NumBlocks; LbaIndex += 1) {\r
1018 if ((FtwDevice->SpareAreaAddress >= (BaseAddress + FvbMapEntry->Length * (LbaIndex - 1)))\r
1019 && (FtwDevice->SpareAreaAddress < (BaseAddress + FvbMapEntry->Length * LbaIndex))) {\r
1020 //\r
1021 // Get the NumberOfSpareBlock and BlockSize\r
1022 //\r
1023 FtwDevice->FtwSpareLba = LbaIndex - 1;\r
1024 FtwDevice->BlockSize = FvbMapEntry->Length;\r
1025 FtwDevice->NumberOfSpareBlock = FtwDevice->SpareAreaLength / FtwDevice->BlockSize;\r
1026 //\r
1027 // Check the range of spare area to make sure that it's in FV range\r
1028 //\r
1029 if ((FtwDevice->FtwSpareLba + FtwDevice->NumberOfSpareBlock) > FvbMapEntry->NumBlocks) {\r
1030 DEBUG ((EFI_D_ERROR, "Ftw: Spare area is out of FV range\n"));\r
1031 FreePool (FtwDevice);\r
1032 return EFI_ABORTED;\r
1033 }\r
1034 break;\r
1035 }\r
1036 }\r
1037 }\r
1038 }\r
1039 }\r
1040\r
1041 //\r
1042 // Calculate the start LBA of working block. Working block is an area which\r
1043 // contains working space in its last block and has the same size as spare\r
1044 // block, unless there are not enough blocks before the block that contains\r
1045 // working space.\r
1046 //\r
1047 FtwDevice->FtwWorkBlockLba = FtwDevice->FtwWorkSpaceLba - FtwDevice->NumberOfSpareBlock + 1;\r
1048 if ((INT64) (FtwDevice->FtwWorkBlockLba) < 0) {\r
1049 DEBUG ((EFI_D_ERROR, "Ftw: The spare block range is too large than the working block range!\n"));\r
1050 FreePool (FtwDevice);\r
1051 return EFI_ABORTED;\r
1052 }\r
1053\r
1054 if ((FtwDevice->FtwFvBlock == NULL) ||\r
1055 (FtwDevice->FtwBackupFvb == NULL) ||\r
1056 (FtwDevice->FtwWorkSpaceLba == (EFI_LBA) (-1)) ||\r
1057 (FtwDevice->FtwSpareLba == (EFI_LBA) (-1))\r
1058 ) {\r
1059 DEBUG ((EFI_D_ERROR, "Ftw: Working or spare FVB not ready\n"));\r
1060 FreePool (FtwDevice);\r
1061 return EFI_ABORTED;\r
1062 }\r
1063 //\r
1064 // Initialize other parameters, and set WorkSpace as FTW_ERASED_BYTE.\r
1065 //\r
1066 FtwDevice->FtwWorkSpace = (UINT8 *) (FtwDevice + 1);\r
1067 FtwDevice->FtwWorkSpaceHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER *) FtwDevice->FtwWorkSpace;\r
1068\r
1069 FtwDevice->FtwLastWriteHeader = NULL;\r
1070 FtwDevice->FtwLastWriteRecord = NULL;\r
1071\r
1072 //\r
1073 // Refresh the working space data from working block\r
1074 //\r
1075 Status = WorkSpaceRefresh (FtwDevice);\r
1076 if (EFI_ERROR (Status)) {\r
1077 goto Recovery;\r
1078 }\r
1079 //\r
1080 // If the working block workspace is not valid, try the spare block\r
1081 //\r
1082 if (!IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
1083 //\r
1084 // Read from spare block\r
1085 //\r
1086 Length = FtwDevice->FtwWorkSpaceSize;\r
1087 Status = FtwDevice->FtwBackupFvb->Read (\r
1088 FtwDevice->FtwBackupFvb,\r
1089 FtwDevice->FtwSpareLba,\r
1090 FtwDevice->FtwWorkSpaceBase,\r
1091 &Length,\r
1092 FtwDevice->FtwWorkSpace\r
1093 );\r
1094 if (EFI_ERROR (Status)) {\r
1095 goto Recovery;\r
1096 }\r
1097 //\r
1098 // If spare block is valid, then replace working block content.\r
1099 //\r
1100 if (IsValidWorkSpace (FtwDevice->FtwWorkSpaceHeader)) {\r
1101 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
1102 DEBUG ((EFI_D_ERROR, "Ftw: Restart working block update in Init() - %r\n", Status));\r
1103 FtwAbort (&FtwDevice->FtwInstance);\r
1104 //\r
1105 // Refresh work space.\r
1106 //\r
1107 Status = WorkSpaceRefresh (FtwDevice);\r
1108 if (EFI_ERROR (Status)) {\r
1109 goto Recovery;\r
1110 }\r
1111 } else {\r
1112 DEBUG ((EFI_D_ERROR, "Ftw: Both are invalid, init workspace\n"));\r
1113 //\r
1114 // If both are invalid, then initialize work space.\r
1115 //\r
1116 SetMem (\r
1117 FtwDevice->FtwWorkSpace,\r
1118 FtwDevice->FtwWorkSpaceSize,\r
1119 FTW_ERASED_BYTE\r
1120 );\r
1121 InitWorkSpaceHeader (FtwDevice->FtwWorkSpaceHeader);\r
1122 //\r
1123 // Initialize the work space\r
1124 //\r
1125 Status = FtwReclaimWorkSpace (FtwDevice, FALSE);\r
1126 if (EFI_ERROR (Status)) {\r
1127 goto Recovery;\r
1128 }\r
1129 }\r
1130 }\r
1131\r
1132 //\r
1133 // If the FtwDevice->FtwLastWriteRecord is 1st record of write header &&\r
1134 // (! SpareComplete) THEN call Abort().\r
1135 //\r
1136 if ((FtwDevice->FtwLastWriteHeader->HeaderAllocated == FTW_VALID_STATE) &&\r
1137 (FtwDevice->FtwLastWriteRecord->SpareComplete != FTW_VALID_STATE) &&\r
1138 IsFirstRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
1139 ) {\r
1140 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find first record not SpareCompleted, abort()\n"));\r
1141 FtwAbort (&FtwDevice->FtwInstance);\r
1142 }\r
1143 //\r
1144 // If Header is incompleted and the last record has completed, then\r
1145 // call Abort() to set the Header->Complete FLAG.\r
1146 //\r
1147 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
1148 (FtwDevice->FtwLastWriteRecord->DestinationComplete == FTW_VALID_STATE) &&\r
1149 IsLastRecordOfWrites (FtwDevice->FtwLastWriteHeader, FtwDevice->FtwLastWriteRecord)\r
1150 ) {\r
1151 DEBUG ((EFI_D_ERROR, "Ftw: Init.. find last record completed but header not, abort()\n"));\r
1152 FtwAbort (&FtwDevice->FtwInstance);\r
1153 }\r
1154 //\r
1155 // To check the workspace buffer following last Write header/records is EMPTY or not.\r
1156 // If it's not EMPTY, FTW also need to call reclaim().\r
1157 //\r
1158 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
1159 Offset = (UINT8 *) FtwHeader - FtwDevice->FtwWorkSpace;\r
1160 if (FtwDevice->FtwWorkSpace[Offset] != FTW_ERASED_BYTE) {\r
1161 Offset += WRITE_TOTAL_SIZE (FtwHeader->NumberOfWrites, FtwHeader->PrivateDataSize);\r
1162 }\r
1163\r
1164 if (!IsErasedFlashBuffer (\r
1165 FtwDevice->FtwWorkSpace + Offset,\r
1166 FtwDevice->FtwWorkSpaceSize - Offset\r
1167 )) {\r
1168 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
1169 if (EFI_ERROR (Status)) {\r
1170 goto Recovery;\r
1171 }\r
1172 }\r
1173 //\r
1174 // Restart if it's boot block\r
1175 //\r
1176 if ((FtwDevice->FtwLastWriteHeader->Complete != FTW_VALID_STATE) &&\r
1177 (FtwDevice->FtwLastWriteRecord->SpareComplete == FTW_VALID_STATE)\r
1178 ) {\r
1179 if (FtwDevice->FtwLastWriteRecord->BootBlockUpdate == FTW_VALID_STATE) {\r
1180 Status = FlushSpareBlockToBootBlock (FtwDevice);\r
1181 DEBUG ((EFI_D_ERROR, "Ftw: Restart boot block update - %r\n", Status));\r
1182 if (EFI_ERROR (Status)) {\r
1183 goto Recovery;\r
1184 }\r
1185 \r
1186 FtwAbort (&FtwDevice->FtwInstance);\r
1187 } else {\r
1188 //\r
1189 // if (SpareCompleted) THEN Restart to fault tolerant write.\r
1190 //\r
1191 FvbHandle = GetFvbByAddress (FtwDevice->FtwLastWriteRecord->FvBaseAddress, &Fvb);\r
1192 if (FvbHandle != NULL) {\r
1193 Status = FtwRestart (&FtwDevice->FtwInstance, FvbHandle);\r
1194 DEBUG ((EFI_D_ERROR, "FtwLite: Restart last write - %r\n", Status));\r
1195 if (EFI_ERROR (Status)) {\r
1196 goto Recovery;\r
1197 }\r
1198 }\r
1199 FtwAbort (&FtwDevice->FtwInstance);\r
1200 }\r
1201 }\r
1202\r
1203 //\r
1204 // Hook the protocol API\r
1205 //\r
1206 FtwDevice->FtwInstance.GetMaxBlockSize = FtwGetMaxBlockSize;\r
1207 FtwDevice->FtwInstance.Allocate = FtwAllocate;\r
1208 FtwDevice->FtwInstance.Write = FtwWrite;\r
1209 FtwDevice->FtwInstance.Restart = FtwRestart;\r
1210 FtwDevice->FtwInstance.Abort = FtwAbort;\r
1211 FtwDevice->FtwInstance.GetLastWrite = FtwGetLastWrite;\r
1212\r
1213 //\r
1214 // Install protocol interface\r
1215 //\r
1216 Status = gBS->InstallProtocolInterface (\r
1217 &FtwDevice->Handle,\r
1218 &gEfiFaultTolerantWriteProtocolGuid,\r
1219 EFI_NATIVE_INTERFACE,\r
1220 &FtwDevice->FtwInstance\r
1221 );\r
1222 if (EFI_ERROR (Status)) {\r
1223 goto Recovery;\r
1224 }\r
1225\r
1226 return EFI_SUCCESS;\r
1227\r
1228Recovery:\r
1229\r
1230 if (FtwDevice != NULL) {\r
1231 FreePool (FtwDevice);\r
1232 }\r
1233\r
1234 DEBUG ((EFI_D_ERROR, "Ftw: Severe Error occurs, need to recovery\n"));\r
1235\r
1236 return EFI_VOLUME_CORRUPTED;\r
1237}\r