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