]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWrite.c
MdeModulePkg: Variable drivers robustly handle crashes during Reclaim().
[mirror_edk2.git] / MdeModulePkg / Universal / FaultTolerantWriteDxe / FaultTolerantWrite.c
CommitLineData
85e923a5
LG
1/** @file\r
2\r
8a2d4996 3 These are the common Fault Tolerant Write (FTW) functions that are shared \r
4 by DXE FTW driver and SMM FTW driver.\r
85e923a5 5\r
3e02ebb2 6Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 7This program and the accompanying materials \r
85e923a5
LG
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php \r
11 \r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
14\r
15**/\r
16\r
17#include "FaultTolerantWrite.h"\r
18\r
85e923a5
LG
19//\r
20// Fault Tolerant Write Protocol API\r
21//\r
22/**\r
23 Query the largest block that may be updated in a fault tolerant manner.\r
24\r
25\r
26 @param This The pointer to this protocol instance. \r
27 @param BlockSize A pointer to a caller allocated UINTN that is updated to\r
28 indicate the size of the largest block that can be updated.\r
29\r
30 @return EFI_SUCCESS The function completed successfully\r
31\r
32**/\r
33EFI_STATUS\r
34EFIAPI\r
35FtwGetMaxBlockSize (\r
36 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
37 OUT UINTN *BlockSize\r
38 )\r
39{\r
40 EFI_FTW_DEVICE *FtwDevice;\r
41\r
42 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
43 return EFI_UNSUPPORTED;\r
44 }\r
45\r
46 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
47\r
48 *BlockSize = FtwDevice->SpareAreaLength;\r
49\r
50 return EFI_SUCCESS;\r
51}\r
52\r
53/**\r
54 Allocates space for the protocol to maintain information about writes.\r
55 Since writes must be completed in a fault tolerant manner and multiple\r
56 updates will require more resources to be successful, this function\r
57 enables the protocol to ensure that enough space exists to track\r
58 information about the upcoming writes.\r
59\r
60 All writes must be completed or aborted before another fault tolerant write can occur.\r
61\r
62 @param This The pointer to this protocol instance. \r
63 @param CallerId The GUID identifying the write.\r
64 @param PrivateDataSize The size of the caller's private data\r
65 that must be recorded for each write.\r
66 @param NumberOfWrites The number of fault tolerant block writes\r
67 that will need to occur.\r
68\r
69 @return EFI_SUCCESS The function completed successfully\r
70 @retval EFI_ABORTED The function could not complete successfully.\r
71 @retval EFI_ACCESS_DENIED All allocated writes have not been completed.\r
72\r
73**/\r
74EFI_STATUS\r
75EFIAPI\r
76FtwAllocate (\r
77 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
78 IN EFI_GUID *CallerId,\r
79 IN UINTN PrivateDataSize,\r
80 IN UINTN NumberOfWrites\r
81 )\r
82{\r
83 EFI_STATUS Status;\r
84 UINTN Length;\r
85 UINTN Offset;\r
86 EFI_FTW_DEVICE *FtwDevice;\r
87 EFI_FAULT_TOLERANT_WRITE_HEADER *FtwHeader;\r
88\r
89 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
90\r
91 Status = WorkSpaceRefresh (FtwDevice);\r
92 if (EFI_ERROR (Status)) {\r
93 return EFI_ABORTED;\r
94 }\r
95 //\r
96 // Check if there is enough space for the coming allocation\r
97 //\r
3e02ebb2 98 if (FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceHeader->WriteQueueSize) {\r
85e923a5
LG
99 DEBUG ((EFI_D_ERROR, "Ftw: Allocate() request exceed Workspace, Caller: %g\n", CallerId));\r
100 return EFI_BUFFER_TOO_SMALL;\r
101 }\r
102 //\r
103 // Find the last write header and record.\r
104 // If the FtwHeader is complete, skip the completed last write header/records\r
105 //\r
106 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
107\r
108 //\r
109 // Previous write has not completed, access denied.\r
110 //\r
111 if ((FtwHeader->HeaderAllocated == FTW_VALID_STATE) || (FtwHeader->WritesAllocated == FTW_VALID_STATE)) {\r
112 return EFI_ACCESS_DENIED;\r
113 }\r
114 //\r
115 // If workspace is not enough, then reclaim workspace\r
116 //\r
117 Offset = (UINT8 *) FtwHeader - (UINT8 *) FtwDevice->FtwWorkSpace;\r
3e02ebb2 118 if (Offset + FTW_WRITE_TOTAL_SIZE (NumberOfWrites, PrivateDataSize) > FtwDevice->FtwWorkSpaceSize) {\r
85e923a5
LG
119 Status = FtwReclaimWorkSpace (FtwDevice, TRUE);\r
120 if (EFI_ERROR (Status)) {\r
121 return EFI_ABORTED;\r
122 }\r
123\r
124 FtwHeader = FtwDevice->FtwLastWriteHeader;\r
125 }\r
126 //\r
127 // Prepare FTW write header,\r
128 // overwrite the buffer and write to workspace.\r
129 //\r
130 FtwHeader->WritesAllocated = FTW_INVALID_STATE;\r
131 FtwHeader->Complete = FTW_INVALID_STATE;\r
132 CopyMem (&FtwHeader->CallerId, CallerId, sizeof (EFI_GUID));\r
133 FtwHeader->NumberOfWrites = NumberOfWrites;\r
134 FtwHeader->PrivateDataSize = PrivateDataSize;\r
135 FtwHeader->HeaderAllocated = FTW_VALID_STATE;\r
136\r
137 Length = sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER);\r
138 Status = FtwDevice->FtwFvBlock->Write (\r
139 FtwDevice->FtwFvBlock,\r
140 FtwDevice->FtwWorkSpaceLba,\r
141 FtwDevice->FtwWorkSpaceBase + Offset,\r
142 &Length,\r
143 (UINT8 *) FtwHeader\r
144 );\r
145 if (EFI_ERROR (Status)) {\r
146 return EFI_ABORTED;\r
147 }\r
148 //\r
149 // Update Header->WriteAllocated as VALID\r
150 //\r
151 Status = FtwUpdateFvState (\r
152 FtwDevice->FtwFvBlock,\r
153 FtwDevice->FtwWorkSpaceLba,\r
154 FtwDevice->FtwWorkSpaceBase + Offset,\r
155 WRITES_ALLOCATED\r
156 );\r
157 if (EFI_ERROR (Status)) {\r
158 return EFI_ABORTED;\r
159 }\r
160\r
161 DEBUG (\r
162 (EFI_D_ERROR,\r
163 "Ftw: Allocate() success, Caller:%g, # %d\n",\r
164 CallerId,\r
165 NumberOfWrites)\r
166 );\r
167\r
168 return EFI_SUCCESS;\r
169}\r
170\r
171\r
172/**\r
173 Write a record with fault tolerant mannaer.\r
174 Since the content has already backuped in spare block, the write is\r
175 guaranteed to be completed with fault tolerant manner.\r
176\r
177 @param This The pointer to this protocol instance. \r
178 @param Fvb The FVB protocol that provides services for\r
179 reading, writing, and erasing the target block.\r
180\r
181 @retval EFI_SUCCESS The function completed successfully\r
182 @retval EFI_ABORTED The function could not complete successfully\r
183\r
184**/\r
185EFI_STATUS\r
186FtwWriteRecord (\r
187 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
188 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb\r
189 )\r
190{\r
191 EFI_STATUS Status;\r
192 EFI_FTW_DEVICE *FtwDevice;\r
193 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
194 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
195 UINTN Offset;\r
d26c7e82 196 EFI_LBA WorkSpaceLbaOffset;\r
85e923a5
LG
197\r
198 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
199\r
d26c7e82
SZ
200 WorkSpaceLbaOffset = FtwDevice->FtwWorkSpaceLba - FtwDevice->FtwWorkBlockLba;\r
201\r
85e923a5
LG
202 //\r
203 // Spare Complete but Destination not complete,\r
8a2d4996 204 // Recover the target block with the spare block.\r
85e923a5
LG
205 //\r
206 Header = FtwDevice->FtwLastWriteHeader;\r
207 Record = FtwDevice->FtwLastWriteRecord;\r
208\r
209 //\r
210 // IF target block is working block, THEN Flush Spare Block To Working Block;\r
211 // ELSE flush spare block to target block, which may be boot block after all.\r
212 //\r
213 if (IsWorkingBlock (FtwDevice, Fvb, Record->Lba)) {\r
214 //\r
215 // If target block is working block,\r
216 // it also need to set SPARE_COMPLETED to spare block.\r
217 //\r
218 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
219 Status = FtwUpdateFvState (\r
220 FtwDevice->FtwBackupFvb,\r
d26c7e82 221 FtwDevice->FtwSpareLba + WorkSpaceLbaOffset,\r
85e923a5
LG
222 FtwDevice->FtwWorkSpaceBase + Offset,\r
223 SPARE_COMPLETED\r
224 );\r
225 if (EFI_ERROR (Status)) {\r
226 return EFI_ABORTED;\r
227 }\r
228\r
229 Status = FlushSpareBlockToWorkingBlock (FtwDevice);\r
230 } else if (IsBootBlock (FtwDevice, Fvb, Record->Lba)) {\r
231 //\r
232 // Update boot block\r
233 //\r
234 Status = FlushSpareBlockToBootBlock (FtwDevice);\r
235 } else {\r
236 //\r
237 // Update blocks other than working block or boot block\r
238 //\r
239 Status = FlushSpareBlockToTargetBlock (FtwDevice, Fvb, Record->Lba);\r
240 }\r
241\r
242 if (EFI_ERROR (Status)) {\r
243 return EFI_ABORTED;\r
244 }\r
245 //\r
246 // Record the DestionationComplete in record\r
247 //\r
248 Offset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
249 Status = FtwUpdateFvState (\r
250 FtwDevice->FtwFvBlock,\r
251 FtwDevice->FtwWorkSpaceLba,\r
252 FtwDevice->FtwWorkSpaceBase + Offset,\r
253 DEST_COMPLETED\r
254 );\r
255 if (EFI_ERROR (Status)) {\r
256 return EFI_ABORTED;\r
257 }\r
258\r
259 Record->DestinationComplete = FTW_VALID_STATE;\r
260\r
261 //\r
262 // If this is the last Write in these write sequence,\r
263 // set the complete flag of write header.\r
264 //\r
265 if (IsLastRecordOfWrites (Header, Record)) {\r
266 Offset = (UINT8 *) Header - FtwDevice->FtwWorkSpace;\r
267 Status = FtwUpdateFvState (\r
268 FtwDevice->FtwFvBlock,\r
269 FtwDevice->FtwWorkSpaceLba,\r
270 FtwDevice->FtwWorkSpaceBase + Offset,\r
271 WRITES_COMPLETED\r
272 );\r
273 Header->Complete = FTW_VALID_STATE;\r
274 if (EFI_ERROR (Status)) {\r
275 return EFI_ABORTED;\r
276 }\r
277 }\r
278\r
279 return EFI_SUCCESS;\r
280}\r
281\r
282/**\r
283 Starts a target block update. This function will record data about write\r
284 in fault tolerant storage and will complete the write in a recoverable\r
285 manner, ensuring at all times that either the original contents or\r
286 the modified contents are available.\r
287\r
288 @param This The pointer to this protocol instance. \r
289 @param Lba The logical block address of the target block.\r
290 @param Offset The offset within the target block to place the data.\r
291 @param Length The number of bytes to write to the target block.\r
292 @param PrivateData A pointer to private data that the caller requires to\r
293 complete any pending writes in the event of a fault.\r
294 @param FvBlockHandle The handle of FVB protocol that provides services for\r
295 reading, writing, and erasing the target block.\r
296 @param Buffer The data to write.\r
297\r
298 @retval EFI_SUCCESS The function completed successfully \r
299 @retval EFI_ABORTED The function could not complete successfully. \r
300 @retval EFI_BAD_BUFFER_SIZE The input data can't fit within the spare block. \r
301 Offset + *NumBytes > SpareAreaLength.\r
302 @retval EFI_ACCESS_DENIED No writes have been allocated. \r
303 @retval EFI_OUT_OF_RESOURCES Cannot allocate enough memory resource.\r
304 @retval EFI_NOT_FOUND Cannot find FVB protocol by handle.\r
305\r
306**/\r
307EFI_STATUS\r
308EFIAPI\r
309FtwWrite (\r
310 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
311 IN EFI_LBA Lba,\r
312 IN UINTN Offset,\r
313 IN UINTN Length,\r
314 IN VOID *PrivateData,\r
315 IN EFI_HANDLE FvBlockHandle,\r
316 IN VOID *Buffer\r
317 )\r
318{\r
319 EFI_STATUS Status;\r
320 EFI_FTW_DEVICE *FtwDevice;\r
321 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
322 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
323 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
324 UINTN MyLength;\r
325 UINTN MyOffset;\r
326 UINTN MyBufferSize;\r
327 UINT8 *MyBuffer;\r
328 UINTN SpareBufferSize;\r
329 UINT8 *SpareBuffer;\r
330 UINTN Index;\r
331 UINT8 *Ptr;\r
332 EFI_PHYSICAL_ADDRESS FvbPhysicalAddress;\r
333\r
334 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
335\r
336 Status = WorkSpaceRefresh (FtwDevice);\r
337 if (EFI_ERROR (Status)) {\r
338 return EFI_ABORTED;\r
339 }\r
340\r
341 Header = FtwDevice->FtwLastWriteHeader;\r
342 Record = FtwDevice->FtwLastWriteRecord;\r
343 \r
344 if (IsErasedFlashBuffer ((UINT8 *) Header, sizeof (EFI_FAULT_TOLERANT_WRITE_HEADER))) {\r
345 if (PrivateData == NULL) {\r
346 //\r
347 // Ftw Write Header is not allocated.\r
348 // No additional private data, the private data size is zero. Number of record can be set to 1.\r
349 //\r
350 Status = FtwAllocate (This, &gEfiCallerIdGuid, 0, 1);\r
351 if (EFI_ERROR (Status)) {\r
352 return Status;\r
353 }\r
354 } else {\r
355 //\r
356 // Ftw Write Header is not allocated\r
357 // Additional private data is not NULL, the private data size can't be determined.\r
358 //\r
359 DEBUG ((EFI_D_ERROR, "Ftw: no allocates space for write record!\n"));\r
360 DEBUG ((EFI_D_ERROR, "Ftw: Allocate service should be called before Write service!\n"));\r
361 return EFI_NOT_READY;\r
362 }\r
363 }\r
364\r
365 //\r
366 // If Record is out of the range of Header, return access denied.\r
367 //\r
3e02ebb2 368 if (((UINTN)((UINT8 *) Record - (UINT8 *) Header)) > FTW_WRITE_TOTAL_SIZE (Header->NumberOfWrites - 1, Header->PrivateDataSize)) {\r
85e923a5
LG
369 return EFI_ACCESS_DENIED;\r
370 }\r
371\r
372 //\r
373 // Check the COMPLETE flag of last write header\r
374 //\r
375 if (Header->Complete == FTW_VALID_STATE) {\r
376 return EFI_ACCESS_DENIED;\r
377 }\r
378\r
379 if (Record->DestinationComplete == FTW_VALID_STATE) {\r
380 return EFI_ACCESS_DENIED;\r
381 }\r
382\r
383 if ((Record->SpareComplete == FTW_VALID_STATE) && (Record->DestinationComplete != FTW_VALID_STATE)) {\r
384 return EFI_NOT_READY;\r
385 }\r
386 //\r
387 // Check if the input data can fit within the target block\r
388 //\r
389 if ((Offset + Length) > FtwDevice->SpareAreaLength) {\r
390 return EFI_BAD_BUFFER_SIZE;\r
391 }\r
392 //\r
393 // Get the FVB protocol by handle\r
394 //\r
395 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);\r
396 if (EFI_ERROR (Status)) {\r
397 return EFI_NOT_FOUND;\r
398 }\r
399\r
400 Status = Fvb->GetPhysicalAddress (Fvb, &FvbPhysicalAddress);\r
401 if (EFI_ERROR (Status)) {\r
402 DEBUG ((EFI_D_ERROR, "FtwLite: Get FVB physical address - %r\n", Status));\r
403 return EFI_ABORTED;\r
404 }\r
405\r
406 //\r
407 // Set BootBlockUpdate FLAG if it's updating boot block.\r
408 //\r
409 if (IsBootBlock (FtwDevice, Fvb, Lba)) {\r
410 Record->BootBlockUpdate = FTW_VALID_STATE;\r
411 }\r
412 //\r
413 // Write the record to the work space.\r
414 //\r
415 Record->Lba = Lba;\r
416 Record->Offset = Offset;\r
417 Record->Length = Length;\r
3e02ebb2 418 Record->RelativeOffset = (INT64) (FvbPhysicalAddress + (UINTN) Lba * FtwDevice->BlockSize) - (INT64) FtwDevice->SpareAreaAddress;\r
f0480ecf 419 if (PrivateData != NULL) {\r
3e02ebb2 420 CopyMem ((Record + 1), PrivateData, (UINTN) Header->PrivateDataSize);\r
f0480ecf 421 }\r
85e923a5
LG
422\r
423 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
3e02ebb2 424 MyLength = FTW_RECORD_SIZE (Header->PrivateDataSize);\r
85e923a5
LG
425\r
426 Status = FtwDevice->FtwFvBlock->Write (\r
427 FtwDevice->FtwFvBlock,\r
428 FtwDevice->FtwWorkSpaceLba,\r
429 FtwDevice->FtwWorkSpaceBase + MyOffset,\r
430 &MyLength,\r
431 (UINT8 *) Record\r
432 );\r
433 if (EFI_ERROR (Status)) {\r
434 return EFI_ABORTED;\r
435 }\r
436 //\r
437 // Record has written to working block, then do the data.\r
438 //\r
439 //\r
440 // Allocate a memory buffer\r
441 //\r
442 MyBufferSize = FtwDevice->SpareAreaLength;\r
443 MyBuffer = AllocatePool (MyBufferSize);\r
444 if (MyBuffer == NULL) {\r
445 return EFI_OUT_OF_RESOURCES;\r
446 }\r
447 //\r
448 // Read all original data from target block to memory buffer\r
449 //\r
450 Ptr = MyBuffer;\r
451 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
452 MyLength = FtwDevice->BlockSize;\r
453 Status = Fvb->Read (Fvb, Lba + Index, 0, &MyLength, Ptr);\r
454 if (EFI_ERROR (Status)) {\r
455 FreePool (MyBuffer);\r
456 return EFI_ABORTED;\r
457 }\r
458\r
459 Ptr += MyLength;\r
460 }\r
461 //\r
462 // Overwrite the updating range data with\r
463 // the input buffer content\r
464 //\r
465 CopyMem (MyBuffer + Offset, Buffer, Length);\r
466\r
467 //\r
468 // Try to keep the content of spare block\r
469 // Save spare block into a spare backup memory buffer (Sparebuffer)\r
470 //\r
471 SpareBufferSize = FtwDevice->SpareAreaLength;\r
472 SpareBuffer = AllocatePool (SpareBufferSize);\r
473 if (SpareBuffer == NULL) {\r
474 FreePool (MyBuffer);\r
475 return EFI_OUT_OF_RESOURCES;\r
476 }\r
477\r
478 Ptr = SpareBuffer;\r
479 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
480 MyLength = FtwDevice->BlockSize;\r
481 Status = FtwDevice->FtwBackupFvb->Read (\r
482 FtwDevice->FtwBackupFvb,\r
483 FtwDevice->FtwSpareLba + Index,\r
484 0,\r
485 &MyLength,\r
486 Ptr\r
487 );\r
488 if (EFI_ERROR (Status)) {\r
489 FreePool (MyBuffer);\r
490 FreePool (SpareBuffer);\r
491 return EFI_ABORTED;\r
492 }\r
493\r
494 Ptr += MyLength;\r
495 }\r
496 //\r
497 // Write the memory buffer to spare block\r
498 //\r
499 Status = FtwEraseSpareBlock (FtwDevice);\r
500 Ptr = MyBuffer;\r
501 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
502 MyLength = FtwDevice->BlockSize;\r
503 Status = FtwDevice->FtwBackupFvb->Write (\r
504 FtwDevice->FtwBackupFvb,\r
505 FtwDevice->FtwSpareLba + Index,\r
506 0,\r
507 &MyLength,\r
508 Ptr\r
509 );\r
510 if (EFI_ERROR (Status)) {\r
511 FreePool (MyBuffer);\r
512 FreePool (SpareBuffer);\r
513 return EFI_ABORTED;\r
514 }\r
515\r
516 Ptr += MyLength;\r
517 }\r
518 //\r
519 // Free MyBuffer\r
520 //\r
521 FreePool (MyBuffer);\r
522\r
523 //\r
524 // Set the SpareComplete in the FTW record,\r
525 //\r
526 MyOffset = (UINT8 *) Record - FtwDevice->FtwWorkSpace;\r
527 Status = FtwUpdateFvState (\r
528 FtwDevice->FtwFvBlock,\r
529 FtwDevice->FtwWorkSpaceLba,\r
530 FtwDevice->FtwWorkSpaceBase + MyOffset,\r
531 SPARE_COMPLETED\r
532 );\r
533 if (EFI_ERROR (Status)) {\r
534 FreePool (SpareBuffer);\r
535 return EFI_ABORTED;\r
536 }\r
537\r
538 Record->SpareComplete = FTW_VALID_STATE;\r
539\r
540 //\r
541 // Since the content has already backuped in spare block, the write is\r
542 // guaranteed to be completed with fault tolerant manner.\r
543 //\r
544 Status = FtwWriteRecord (This, Fvb);\r
545 if (EFI_ERROR (Status)) {\r
546 FreePool (SpareBuffer);\r
547 return EFI_ABORTED;\r
548 }\r
549 //\r
550 // Restore spare backup buffer into spare block , if no failure happened during FtwWrite.\r
551 //\r
552 Status = FtwEraseSpareBlock (FtwDevice);\r
553 Ptr = SpareBuffer;\r
554 for (Index = 0; Index < FtwDevice->NumberOfSpareBlock; Index += 1) {\r
555 MyLength = FtwDevice->BlockSize;\r
556 Status = FtwDevice->FtwBackupFvb->Write (\r
557 FtwDevice->FtwBackupFvb,\r
558 FtwDevice->FtwSpareLba + Index,\r
559 0,\r
560 &MyLength,\r
561 Ptr\r
562 );\r
563 if (EFI_ERROR (Status)) {\r
564 FreePool (SpareBuffer);\r
565 return EFI_ABORTED;\r
566 }\r
567\r
568 Ptr += MyLength;\r
569 }\r
570 //\r
571 // All success.\r
572 //\r
573 FreePool (SpareBuffer);\r
574\r
575 DEBUG (\r
576 (EFI_D_ERROR,\r
577 "Ftw: Write() success, (Lba:Offset)=(%lx:0x%x), Length: 0x%x\n",\r
578 Lba,\r
579 Offset,\r
580 Length)\r
581 );\r
582\r
583 return EFI_SUCCESS;\r
584}\r
585\r
586/**\r
587 Restarts a previously interrupted write. The caller must provide the\r
588 block protocol needed to complete the interrupted write.\r
589\r
590 @param This The pointer to this protocol instance. \r
591 @param FvBlockHandle The handle of FVB protocol that provides services for\r
592 reading, writing, and erasing the target block.\r
593\r
594 @retval EFI_SUCCESS The function completed successfully\r
595 @retval EFI_ACCESS_DENIED No pending writes exist\r
596 @retval EFI_NOT_FOUND FVB protocol not found by the handle\r
597 @retval EFI_ABORTED The function could not complete successfully\r
598\r
599**/\r
600EFI_STATUS\r
601EFIAPI\r
602FtwRestart (\r
603 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
604 IN EFI_HANDLE FvBlockHandle\r
605 )\r
606{\r
607 EFI_STATUS Status;\r
608 EFI_FTW_DEVICE *FtwDevice;\r
609 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
610 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
611 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
612\r
613 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
614\r
615 Status = WorkSpaceRefresh (FtwDevice);\r
616 if (EFI_ERROR (Status)) {\r
617 return EFI_ABORTED;\r
618 }\r
619\r
620 Header = FtwDevice->FtwLastWriteHeader;\r
621 Record = FtwDevice->FtwLastWriteRecord;\r
622\r
623 //\r
624 // Spare Complete but Destination not complete,\r
625 // Recover the targt block with the spare block.\r
626 //\r
627 Status = FtwGetFvbByHandle (FvBlockHandle, &Fvb);\r
628 if (EFI_ERROR (Status)) {\r
629 return EFI_NOT_FOUND;\r
630 }\r
631\r
632 //\r
633 // Check the COMPLETE flag of last write header\r
634 //\r
635 if (Header->Complete == FTW_VALID_STATE) {\r
636 return EFI_ACCESS_DENIED;\r
637 }\r
638\r
639 //\r
640 // Check the flags of last write record\r
641 //\r
642 if (Record->DestinationComplete == FTW_VALID_STATE) {\r
643 return EFI_ACCESS_DENIED;\r
644 }\r
645\r
646 if ((Record->SpareComplete != FTW_VALID_STATE)) {\r
647 return EFI_ABORTED;\r
648 }\r
649\r
650 //\r
651 // Since the content has already backuped in spare block, the write is\r
652 // guaranteed to be completed with fault tolerant manner.\r
653 //\r
654 Status = FtwWriteRecord (This, Fvb);\r
655 if (EFI_ERROR (Status)) {\r
656 return EFI_ABORTED;\r
657 }\r
658\r
659 //\r
660 // Erase Spare block\r
661 // This is restart, no need to keep spareblock content.\r
662 //\r
663 FtwEraseSpareBlock (FtwDevice);\r
664\r
665 DEBUG ((EFI_D_ERROR, "Ftw: Restart() success \n"));\r
666 return EFI_SUCCESS;\r
667}\r
668\r
669/**\r
670 Aborts all previous allocated writes.\r
671\r
672 @param This The pointer to this protocol instance. \r
673\r
674 @retval EFI_SUCCESS The function completed successfully\r
675 @retval EFI_ABORTED The function could not complete successfully.\r
676 @retval EFI_NOT_FOUND No allocated writes exist.\r
677\r
678**/\r
679EFI_STATUS\r
680EFIAPI\r
681FtwAbort (\r
682 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This\r
683 )\r
684{\r
685 EFI_STATUS Status;\r
686 UINTN Offset;\r
687 EFI_FTW_DEVICE *FtwDevice;\r
688\r
689 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
690\r
691 Status = WorkSpaceRefresh (FtwDevice);\r
692 if (EFI_ERROR (Status)) {\r
693 return EFI_ABORTED;\r
694 }\r
695\r
3e02ebb2
SZ
696 if (FtwDevice->FtwLastWriteHeader->HeaderAllocated != FTW_VALID_STATE) {\r
697 return EFI_NOT_FOUND;\r
698 }\r
699\r
85e923a5
LG
700 if (FtwDevice->FtwLastWriteHeader->Complete == FTW_VALID_STATE) {\r
701 return EFI_NOT_FOUND;\r
702 }\r
703 //\r
704 // Update the complete state of the header as VALID and abort.\r
705 //\r
706 Offset = (UINT8 *) FtwDevice->FtwLastWriteHeader - FtwDevice->FtwWorkSpace;\r
707 Status = FtwUpdateFvState (\r
708 FtwDevice->FtwFvBlock,\r
709 FtwDevice->FtwWorkSpaceLba,\r
710 FtwDevice->FtwWorkSpaceBase + Offset,\r
711 WRITES_COMPLETED\r
712 );\r
713 if (EFI_ERROR (Status)) {\r
714 return EFI_ABORTED;\r
715 }\r
716\r
717 FtwDevice->FtwLastWriteHeader->Complete = FTW_VALID_STATE;\r
718\r
719 DEBUG ((EFI_D_ERROR, "Ftw: Abort() success \n"));\r
720 return EFI_SUCCESS;\r
721}\r
722\r
723/**\r
724 Starts a target block update. This records information about the write\r
725 in fault tolerant storage and will complete the write in a recoverable\r
726 manner, ensuring at all times that either the original contents or\r
727 the modified contents are available.\r
728\r
729 @param This The pointer to this protocol instance. \r
730 @param CallerId The GUID identifying the last write.\r
731 @param Lba The logical block address of the last write.\r
732 @param Offset The offset within the block of the last write.\r
733 @param Length The length of the last write.\r
734 @param PrivateDataSize bytes from the private data\r
735 stored for this write.\r
736 @param PrivateData A pointer to a buffer. The function will copy\r
737 @param Complete A Boolean value with TRUE indicating\r
738 that the write was completed.\r
739\r
740 @retval EFI_SUCCESS The function completed successfully\r
741 @retval EFI_ABORTED The function could not complete successfully\r
742 @retval EFI_NOT_FOUND No allocated writes exist\r
743 @retval EFI_BUFFER_TOO_SMALL Input buffer is not larget enough\r
744\r
745**/\r
746EFI_STATUS\r
747EFIAPI\r
748FtwGetLastWrite (\r
749 IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *This,\r
750 OUT EFI_GUID *CallerId,\r
751 OUT EFI_LBA *Lba,\r
752 OUT UINTN *Offset,\r
753 OUT UINTN *Length,\r
754 IN OUT UINTN *PrivateDataSize,\r
755 OUT VOID *PrivateData,\r
756 OUT BOOLEAN *Complete\r
757 )\r
758{\r
759 EFI_STATUS Status;\r
760 EFI_FTW_DEVICE *FtwDevice;\r
761 EFI_FAULT_TOLERANT_WRITE_HEADER *Header;\r
762 EFI_FAULT_TOLERANT_WRITE_RECORD *Record;\r
763\r
764 if (!FeaturePcdGet(PcdFullFtwServiceEnable)) {\r
765 return EFI_UNSUPPORTED;\r
766 }\r
767\r
768 FtwDevice = FTW_CONTEXT_FROM_THIS (This);\r
769\r
770 Status = WorkSpaceRefresh (FtwDevice);\r
771 if (EFI_ERROR (Status)) {\r
772 return EFI_ABORTED;\r
773 }\r
774\r
775 Header = FtwDevice->FtwLastWriteHeader;\r
776 Record = FtwDevice->FtwLastWriteRecord;\r
777\r
778 //\r
779 // If Header is incompleted and the last record has completed, then\r
780 // call Abort() to set the Header->Complete FLAG.\r
781 //\r
782 if ((Header->Complete != FTW_VALID_STATE) &&\r
783 (Record->DestinationComplete == FTW_VALID_STATE) &&\r
784 IsLastRecordOfWrites (Header, Record)\r
785 ) {\r
786\r
787 Status = FtwAbort (This);\r
788 *Complete = TRUE;\r
789 return EFI_NOT_FOUND;\r
790 }\r
791 //\r
792 // If there is no write header/record, return not found.\r
793 //\r
794 if (Header->HeaderAllocated != FTW_VALID_STATE) {\r
795 *Complete = TRUE;\r
796 return EFI_NOT_FOUND;\r
797 }\r
798 //\r
799 // If this record SpareComplete has not set, then it can not restart.\r
800 //\r
801 if (Record->SpareComplete != FTW_VALID_STATE) {\r
f0480ecf
LG
802 Status = GetPreviousRecordOfWrites (Header, &Record);\r
803 if (EFI_ERROR (Status)) {\r
85e923a5 804 FtwAbort (This);\r
85e923a5
LG
805 *Complete = TRUE;\r
806 return EFI_NOT_FOUND;\r
85e923a5 807 }\r
d2fbaaab 808 ASSERT (Record != NULL);\r
85e923a5 809 }\r
f0480ecf 810\r
85e923a5
LG
811 //\r
812 // Fill all the requested values\r
813 //\r
814 CopyMem (CallerId, &Header->CallerId, sizeof (EFI_GUID));\r
815 *Lba = Record->Lba;\r
3e02ebb2
SZ
816 *Offset = (UINTN) Record->Offset;\r
817 *Length = (UINTN) Record->Length;\r
85e923a5
LG
818 *Complete = (BOOLEAN) (Record->DestinationComplete == FTW_VALID_STATE);\r
819\r
820 if (*PrivateDataSize < Header->PrivateDataSize) {\r
3e02ebb2 821 *PrivateDataSize = (UINTN) Header->PrivateDataSize;\r
85e923a5
LG
822 PrivateData = NULL;\r
823 Status = EFI_BUFFER_TOO_SMALL;\r
824 } else {\r
3e02ebb2 825 *PrivateDataSize = (UINTN) Header->PrivateDataSize;\r
85e923a5
LG
826 CopyMem (PrivateData, Record + 1, *PrivateDataSize);\r
827 Status = EFI_SUCCESS;\r
828 }\r
829\r
830 DEBUG ((EFI_D_ERROR, "Ftw: GetLasetWrite() success\n"));\r
831\r
832 return Status;\r
833}\r
834\r