1 /** @file
2   Functions in this file will program the image into flash area.
3 
4   Copyright (c) 2002 - 2018, Intel Corporation. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include "UpdateDriver.h"
11 
12 /**
13   Write a block size data into flash.
14 
15   @param FvbProtocol     Pointer to FVB protocol.
16   @param Lba             Logic block index to be updated.
17   @param BlockSize       Block size
18   @param Buffer          Buffer data to be written.
19 
20   @retval EFI_SUCCESS   Write data successfully.
21   @retval other errors  Write data failed.
22 
23 **/
24 EFI_STATUS
UpdateOneBlock(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_LBA Lba,IN UINTN BlockSize,IN UINT8 * Buffer)25 UpdateOneBlock (
26   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
27   IN EFI_LBA                            Lba,
28   IN UINTN                              BlockSize,
29   IN UINT8                              *Buffer
30   )
31 {
32   EFI_STATUS                            Status;
33   UINTN                                 Size;
34 
35   //
36   // First erase the block
37   //
38   Status                = FvbProtocol->EraseBlocks (
39                                          FvbProtocol,
40                                          Lba,                        // Lba
41                                          1,                          // NumOfBlocks
42                                          EFI_LBA_LIST_TERMINATOR
43                                          );
44   if (EFI_ERROR (Status)) {
45     return Status;
46   }
47 
48   //
49   // Write the block
50   //
51   Size                  = BlockSize;
52   Status                = FvbProtocol->Write (
53                                          FvbProtocol,
54                                          Lba,                        // Lba
55                                          0,                          // Offset
56                                          &Size,                      // Size
57                                          Buffer                      // Buffer
58                                          );
59   if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
60     return Status;
61   }
62 
63   return EFI_SUCCESS;
64 }
65 
66 /**
67   Write buffer data in a flash block.
68 
69   @param FvbProtocol     Pointer to FVB protocol.
70   @param Lba             Logic block index to be updated.
71   @param Offset          The offset within the block.
72   @param Length          Size of buffer to be updated.
73   @param BlockSize       Block size.
74   @param Buffer          Buffer data to be updated.
75 
76   @retval EFI_SUCCESS   Write data successfully.
77   @retval other errors  Write data failed.
78 
79 **/
80 EFI_STATUS
UpdateBufferInOneBlock(IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_LBA Lba,IN UINTN Offset,IN UINTN Length,IN UINTN BlockSize,IN UINT8 * Buffer)81 UpdateBufferInOneBlock (
82   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
83   IN EFI_LBA                            Lba,
84   IN UINTN                              Offset,
85   IN UINTN                              Length,
86   IN UINTN                              BlockSize,
87   IN UINT8                              *Buffer
88   )
89 {
90   EFI_STATUS                            Status;
91   UINTN                                 Size;
92   UINT8                                 *ReservedBuffer;
93 
94   //
95   // If we are going to update a whole block
96   //
97   if ((Offset == 0) && (Length == BlockSize)) {
98     Status              = UpdateOneBlock (
99                             FvbProtocol,
100                             Lba,
101                             BlockSize,
102                             Buffer
103                             );
104     return Status;
105   }
106 
107   //
108   // If it is not a full block update, we need to coalesce data in
109   // the block that is not going to be updated and new data together.
110   //
111 
112   //
113   // Allocate a reserved buffer to make up the final buffer for update
114   //
115   ReservedBuffer        = NULL;
116   ReservedBuffer = AllocatePool (BlockSize);
117   if (ReservedBuffer == NULL) {
118     return EFI_OUT_OF_RESOURCES;
119   }
120   //
121   // First get the original content of the block
122   //
123   Size                  = BlockSize;
124   Status                = FvbProtocol->Read (
125                                          FvbProtocol,
126                                          Lba,
127                                          0,
128                                          &Size,
129                                          ReservedBuffer
130                                          );
131   if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
132     FreePool (ReservedBuffer);
133     return Status;
134   }
135 
136   //
137   // Overwrite the reserved buffer with new content
138   //
139   CopyMem (ReservedBuffer + Offset, Buffer, Length);
140 
141   Status                = UpdateOneBlock (
142                             FvbProtocol,
143                             Lba,
144                             BlockSize,
145                             ReservedBuffer
146                             );
147 
148   FreePool (ReservedBuffer);
149 
150   return Status;
151 }
152 
153 /**
154   Get the last write log, and check the status of last write.
155   If not complete, restart will be taken.
156 
157   @param FvbHandle       Handle of FVB protocol.
158   @param FtwProtocol     FTW protocol instance.
159   @param ConfigData      Config data on updating driver.
160   @param PrivateDataSize bytes from the private data
161                          stored for this write.
162   @param PrivateData     A pointer to a buffer. The function will copy.
163   @param Lba             The logical block address of the last write.
164   @param Offset          The offset within the block of the last write.
165   @param Length          The length of the last write.
166   @param Pending         A Boolean value with TRUE indicating
167                          that the write was completed.
168 
169   @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.
170   @retval EFI_ABORTED           The FTW work space is damaged.
171   @retval EFI_NOT_FOUND         The last write is not done by this driver.
172   @retval EFI_SUCCESS           Last write log is got.
173 
174 **/
175 EFI_STATUS
RetrieveLastWrite(IN EFI_HANDLE FvbHandle,IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL * FtwProtocol,IN UPDATE_CONFIG_DATA * ConfigData,IN UINTN PrivateDataSize,IN OUT UPDATE_PRIVATE_DATA * PrivateData,IN OUT EFI_LBA * Lba,IN OUT UINTN * Offset,IN OUT UINTN * Length,IN OUT BOOLEAN * Pending)176 RetrieveLastWrite (
177   IN EFI_HANDLE                         FvbHandle,
178   IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL  *FtwProtocol,
179   IN UPDATE_CONFIG_DATA                 *ConfigData,
180   IN UINTN                              PrivateDataSize,
181   IN OUT UPDATE_PRIVATE_DATA            *PrivateData,
182   IN OUT EFI_LBA                        *Lba,
183   IN OUT UINTN                          *Offset,
184   IN OUT UINTN                          *Length,
185   IN OUT BOOLEAN                        *Pending
186   )
187 {
188   EFI_STATUS                            Status;
189   EFI_GUID                              CallerId;
190   UINTN                                 PrivateBufferSize;
191   BOOLEAN                               Complete;
192   VOID                                  *PrivateDataBuffer;
193 
194   //
195   // Get the last write
196   //
197   *Pending              = FALSE;
198   PrivateBufferSize     = PrivateDataSize;
199   PrivateDataBuffer     = NULL;
200   Status                = FtwProtocol->GetLastWrite (
201                                          FtwProtocol,
202                                          &CallerId,
203                                          Lba,
204                                          Offset,
205                                          Length,
206                                          &PrivateBufferSize,
207                                          PrivateData,
208                                          &Complete
209                                          );
210   if (EFI_ERROR (Status)) {
211     //
212     // If there is no incompleted record, return success.
213     //
214     if ((Status == EFI_NOT_FOUND) && Complete) {
215       return EFI_SUCCESS;
216     } else if (Status == EFI_BUFFER_TOO_SMALL) {
217       //
218       // If buffer too small, reallocate buffer and call getlastwrite again
219       //
220       PrivateDataBuffer = AllocatePool (PrivateBufferSize);
221 
222       if (PrivateDataBuffer == NULL) {
223         return EFI_OUT_OF_RESOURCES;
224       }
225 
226       Status            = FtwProtocol->GetLastWrite (
227                                          FtwProtocol,
228                                          &CallerId,
229                                          Lba,
230                                          Offset,
231                                          Length,
232                                          &PrivateBufferSize,
233                                          PrivateDataBuffer,
234                                          &Complete
235                                          );
236       if (EFI_ERROR (Status)) {
237         FreePool ( PrivateDataBuffer);
238         return EFI_ABORTED;
239       } else {
240         CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize);
241         FreePool (PrivateDataBuffer);
242         PrivateDataBuffer = NULL;
243       }
244     } else {
245       return EFI_ABORTED;
246     }
247   }
248 
249   *Pending              = TRUE;
250 
251   //
252   // If the caller is not the update driver, then return.
253   // The update driver cannot continue to perform the update
254   //
255   if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) {
256     return EFI_NOT_FOUND;
257   }
258 
259   //
260   // Check the private data and see if it is the one I need.
261   //
262   if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) {
263     return EFI_NOT_FOUND;
264   }
265 
266   //
267   // If the caller is the update driver and complete is not true, then restart().
268   //
269   if (!Complete) {
270     //
271     //  Re-start the update
272     //
273     Status              = FtwProtocol->Restart (
274                                          FtwProtocol,
275                                          FvbHandle
276                                          );
277     //
278     // If restart() error, then abort().
279     //
280     if (EFI_ERROR (Status)) {
281       FtwProtocol->Abort (FtwProtocol);
282       //
283       // Now set Pending as FALSE as this record has been cleared
284       //
285       *Pending          = FALSE;
286       return EFI_SUCCESS;
287     }
288 
289   }
290 
291   return Status;
292 }
293 
294 /**
295   Update the whole FV image in fault tolerant write method.
296 
297   @param FvbHandle       Handle of FVB protocol for the updated flash range.
298   @param FvbProtocol     FVB protocol.
299   @param BlockMap        Block array to specify flash area.
300   @param ConfigData      Config data on updating driver.
301   @param ImageBuffer     Image buffer to be updated.
302   @param ImageSize       Image size.
303 
304   @retval EFI_SUCCESS            FV image is writed into flash.
305   @retval EFI_INVALID_PARAMETER  Config data is not valid.
306   @retval EFI_NOT_FOUND          FTW protocol doesn't exist.
307   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
308   @retval EFI_ABORTED            Error happen when update FV.
309 
310 **/
311 EFI_STATUS
FaultTolerantUpdateOnWholeFv(IN EFI_HANDLE FvbHandle,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_FV_BLOCK_MAP_ENTRY * BlockMap,IN UPDATE_CONFIG_DATA * ConfigData,IN UINT8 * ImageBuffer,IN UINTN ImageSize)312 FaultTolerantUpdateOnWholeFv (
313   IN EFI_HANDLE                         FvbHandle,
314   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
315   IN EFI_FV_BLOCK_MAP_ENTRY             *BlockMap,
316   IN UPDATE_CONFIG_DATA                 *ConfigData,
317   IN UINT8                              *ImageBuffer,
318   IN UINTN                              ImageSize
319   )
320 {
321   EFI_STATUS                            Status;
322   EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *FtwProtocol;
323   UINTN                                 MaxBlockSize;
324   UINTN                                 FtwMaxBlockSize;
325   BOOLEAN                               Pending;
326   UPDATE_PRIVATE_DATA                   PrivateData;
327   EFI_LBA                               PendingLba;
328   EFI_LBA                               Lba;
329   UINTN                                 PendingOffset;
330   UINTN                                 Offset;
331   UINTN                                 PendingLength;
332   UINTN                                 Length;
333   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
334   UINTN                                 NumOfBlocks;
335   UINTN                                 Index;
336   UINT8                                 *UpdateBuffer;
337 
338   if ((ConfigData->UpdateType != UpdateWholeFV)
339     || (!ConfigData->FaultTolerant)) {
340     return EFI_INVALID_PARAMETER;
341   }
342 
343   //
344   // Get the FTW protocol
345   //
346   Status                = gBS->LocateProtocol (
347                                  &gEfiFaultTolerantWriteProtocolGuid,
348                                  NULL,
349                                  (VOID **) &FtwProtocol
350                                  );
351   if (EFI_ERROR (Status)) {
352     return EFI_NOT_FOUND;
353   }
354 
355   //
356   // Get the maximum block size of the FV, and number of blocks
357   // NumOfBlocks will be the NumOfUdpates.
358   //
359   MaxBlockSize          = 0;
360   NumOfBlocks           = 0;
361   PtrMap                = BlockMap;
362   while (TRUE) {
363     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
364       break;
365     }
366     if (MaxBlockSize < PtrMap->Length) {
367       MaxBlockSize      = PtrMap->Length;
368     }
369     NumOfBlocks         = NumOfBlocks + PtrMap->NumBlocks;
370     PtrMap++;
371   }
372 
373   FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
374   //
375   // Not enough backup space. return directly
376   //
377   if (FtwMaxBlockSize < MaxBlockSize) {
378     return EFI_OUT_OF_RESOURCES;
379   }
380 
381   PendingLba            = 0;
382   PendingOffset         = 0;
383   PendingLength         = 0;
384   Pending               = FALSE;
385 
386   //
387   // Fault Tolerant Write can only support actual fault tolerance if the write
388   // is a reclaim operation, which means the data buffer (new and old) are
389   // acutally both stored in flash. But for component update write, the data
390   // are now in memory. So we cannot actually recover the data after power
391   // failure.
392   //
393   Status                = RetrieveLastWrite (
394                             FvbHandle,
395                             FtwProtocol,
396                             ConfigData,
397                             sizeof (UPDATE_PRIVATE_DATA),
398                             &PrivateData,
399                             &PendingLba,
400                             &PendingOffset,
401                             &PendingLength,
402                             &Pending
403                             );
404 
405   if (Pending && (Status == EFI_NOT_FOUND)) {
406     //
407     // Cannot continue with the write operation
408     //
409     return EFI_ABORTED;
410   }
411 
412   if (EFI_ERROR(Status)) {
413     return EFI_ABORTED;
414   }
415 
416   //
417   // Currently we start from the pending write if there is any. But as we
418   // are going to update a whole FV, we can just abort last write and start
419   // from the very begining.
420   //
421   if (!Pending) {
422     //
423     // Now allocte the update private data in FTW. If there is pending
424     // write, it has already been allocated and no need to allocate here.
425     //
426     Status              = FtwProtocol->Allocate (
427                                          FtwProtocol,
428                                          &gEfiCallerIdGuid,
429                                          sizeof (UPDATE_PRIVATE_DATA),
430                                          NumOfBlocks
431                                          );
432     if (EFI_ERROR (Status)) {
433       return Status;
434     }
435   }
436 
437   //
438   // Perform the update now. If there are pending writes, we need to
439   // start from the pending write instead of the very beginning.
440   //
441   PtrMap                = BlockMap;
442   Lba                   = 0;
443   Offset                = 0;
444   UpdateBuffer          = ImageBuffer;
445   CopyMem (
446     (VOID *) &PrivateData.FileGuid,
447     (VOID *) &ConfigData->FileGuid,
448      sizeof (EFI_GUID)
449   );
450 
451   while (TRUE) {
452     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
453       break;
454     }
455     Length              = (UINTN)PtrMap->Length;
456     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
457 
458       //
459       // Add an extra check here to see if the pending record is correct
460       //
461       if (Pending && (Lba == PendingLba)) {
462         if ((PendingOffset != Offset) || (PendingLength != Length)) {
463           //
464           // Error.
465           //
466           Status          = EFI_ABORTED;
467           break;
468         }
469       }
470 
471       if ((!Pending) || (Lba >= PendingLba)) {
472         Status            = FtwProtocol->Write (
473                                            FtwProtocol,
474                                            Lba,                  // Lba
475                                            Offset,               // Offset
476                                            Length,               // Size
477                                            &PrivateData,         // Private Data
478                                            FvbHandle,            // FVB handle
479                                            UpdateBuffer          // Buffer
480                                            );
481       }
482 
483       if (EFI_ERROR (Status)) {
484         break;
485       }
486       Lba++;
487       UpdateBuffer      = (UINT8 *) ((UINTN)UpdateBuffer + Length);
488     }
489 
490     if (EFI_ERROR (Status)) {
491       break;
492     }
493     PtrMap++;
494   }
495 
496   return Status;
497 
498 }
499 
500 /**
501   Directly update the whole FV image without fault tolerant write method.
502 
503   @param FvbHandle       Handle of FVB protocol for the updated flash range.
504   @param FvbProtocol     FVB protocol.
505   @param BlockMap        Block array to specify flash area.
506   @param ConfigData      Config data on updating driver.
507   @param ImageBuffer     Image buffer to be updated.
508   @param ImageSize       Image size.
509 
510   @retval EFI_SUCCESS            FV image is writed into flash.
511   @retval EFI_INVALID_PARAMETER  Config data is not valid.
512   @retval EFI_ABORTED            Error happen when update FV.
513 
514 **/
515 EFI_STATUS
NonFaultTolerantUpdateOnWholeFv(IN EFI_HANDLE FvbHandle,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_FV_BLOCK_MAP_ENTRY * BlockMap,IN UPDATE_CONFIG_DATA * ConfigData,IN UINT8 * ImageBuffer,IN UINTN ImageSize)516 NonFaultTolerantUpdateOnWholeFv (
517   IN EFI_HANDLE                         FvbHandle,
518   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
519   IN EFI_FV_BLOCK_MAP_ENTRY             *BlockMap,
520   IN UPDATE_CONFIG_DATA                 *ConfigData,
521   IN UINT8                              *ImageBuffer,
522   IN UINTN                              ImageSize
523   )
524 {
525   EFI_STATUS                            Status;
526   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
527   UINTN                                 Index;
528   EFI_LBA                               UpdateLba;
529   UINT8                                 *UpdateBuffer;
530   UINTN                                 UpdateSize;
531 
532   if ((ConfigData->UpdateType != UpdateWholeFV )
533     || (ConfigData->FaultTolerant)) {
534     return EFI_INVALID_PARAMETER;
535   }
536 
537   Status                = EFI_SUCCESS;
538   PtrMap                = BlockMap;
539   UpdateLba             = 0;
540   UpdateBuffer          = ImageBuffer;
541 
542   //
543   // Perform the update now
544   //
545   while (TRUE) {
546     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
547       break;
548     }
549     UpdateSize          = (UINTN)PtrMap->Length;
550     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
551       Status            = UpdateOneBlock (
552                             FvbProtocol,
553                             UpdateLba,
554                             UpdateSize,
555                             UpdateBuffer
556                             );
557       if (EFI_ERROR (Status)) {
558         break;
559       }
560 
561       UpdateLba++;
562       UpdateBuffer      = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize);
563     }
564 
565     if (EFI_ERROR (Status)) {
566       break;
567     }
568     PtrMap++;
569   }
570 
571   return Status;
572 }
573 
574 /**
575   Update the whole FV image, and reinsall FVB protocol for the updated FV image.
576 
577   @param FvbHandle       Handle of FVB protocol for the updated flash range.
578   @param FvbProtocol     FVB protocol.
579   @param ConfigData      Config data on updating driver.
580   @param ImageBuffer     Image buffer to be updated.
581   @param ImageSize       Image size.
582 
583   @retval EFI_INVALID_PARAMETER  Update type is not UpdateWholeFV.
584                                  Or Image size is not same to the size of whole FV.
585   @retval EFI_OUT_OF_RESOURCES   No enoug memory is allocated.
586   @retval EFI_SUCCESS            FV image is updated, and its FVB protocol is reinstalled.
587 
588 **/
589 EFI_STATUS
PerformUpdateOnWholeFv(IN EFI_HANDLE FvbHandle,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN UPDATE_CONFIG_DATA * ConfigData,IN UINT8 * ImageBuffer,IN UINTN ImageSize)590 PerformUpdateOnWholeFv (
591   IN EFI_HANDLE                         FvbHandle,
592   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
593   IN UPDATE_CONFIG_DATA                 *ConfigData,
594   IN UINT8                              *ImageBuffer,
595   IN UINTN                              ImageSize
596 )
597 {
598   EFI_STATUS                            Status;
599   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
600   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
601   CHAR16                                *TmpStr;
602 
603   if (ConfigData->UpdateType != UpdateWholeFV) {
604     return EFI_INVALID_PARAMETER;
605   }
606 
607   //
608   // Get the header of the firmware volume
609   //
610   FwVolHeader           = NULL;
611   FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength);
612   if (FwVolHeader == NULL) {
613     return EFI_OUT_OF_RESOURCES;
614   }
615   CopyMem (
616     FwVolHeader,
617     (VOID *) ((UINTN) (ConfigData->BaseAddress)),
618     ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength
619     );
620 
621   //
622   // Check if ImageSize is the same as the size of the whole FV
623   //
624   if ((UINT64)ImageSize != FwVolHeader->FvLength) {
625     FreePool (FwVolHeader);
626     return EFI_INVALID_PARAMETER;
627   }
628 
629   //
630   // Print on screen
631   //
632   TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL);
633   if (TmpStr != NULL) {
634     Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress));
635     FreePool (TmpStr);
636   }
637 
638   DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n",
639     ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)));
640 
641   //
642   // Get the block map of the firmware volume
643   //
644   BlockMap              = &(FwVolHeader->BlockMap[0]);
645 
646   //
647   // It is about the same if we are going to fault tolerantly update
648   // a certain FV in our current design. But we divide non-fault tolerant
649   // and fault tolerant udpate here for better maintenance as fault
650   // tolerance may change and may be done more wisely if we have space.
651   //
652   if (ConfigData->FaultTolerant) {
653     Status              = FaultTolerantUpdateOnWholeFv (
654                             FvbHandle,
655                             FvbProtocol,
656                             BlockMap,
657                             ConfigData,
658                             ImageBuffer,
659                             ImageSize
660                             );
661   } else {
662     Status              = NonFaultTolerantUpdateOnWholeFv (
663                             FvbHandle,
664                             FvbProtocol,
665                             BlockMap,
666                             ConfigData,
667                             ImageBuffer,
668                             ImageSize
669                             );
670   }
671 
672   FreePool (FwVolHeader);
673 
674   if (EFI_ERROR (Status)) {
675     return Status;
676   }
677 
678   //
679   // As the whole FV has been replaced, the FV driver shall re-parse the
680   // firmware volume. So re-install FVB protocol here
681   //
682   Status                =  gBS->ReinstallProtocolInterface (
683                                    FvbHandle,
684                                    &gEfiFirmwareVolumeBlockProtocolGuid,
685                                    FvbProtocol,
686                                    FvbProtocol
687                                    );
688 
689   return Status;
690 }
691 
692 /**
693   Update certain file in the FV.
694 
695   @param FvbHandle       Handle of FVB protocol for the updated flash range.
696   @param FvbProtocol     FVB protocol.
697   @param ConfigData      Config data on updating driver.
698   @param ImageBuffer     Image buffer to be updated.
699   @param ImageSize       Image size.
700   @param FileType        FFS file type.
701   @param FileAttributes  FFS file attribute
702 
703   @retval EFI_INVALID_PARAMETER  Update type is not UpdateFvFile.
704                                  Or Image size is not same to the size of whole FV.
705   @retval EFI_UNSUPPORTED        PEIM FFS is unsupported to be updated.
706   @retval EFI_SUCCESS            The FFS file is added into FV.
707 
708 **/
709 EFI_STATUS
PerformUpdateOnFvFile(IN EFI_HANDLE FvbHandle,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN UPDATE_CONFIG_DATA * ConfigData,IN UINT8 * ImageBuffer,IN UINTN ImageSize,IN EFI_FV_FILETYPE FileType,IN EFI_FV_FILE_ATTRIBUTES FileAttributes)710 PerformUpdateOnFvFile (
711   IN EFI_HANDLE                         FvbHandle,
712   IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
713   IN UPDATE_CONFIG_DATA                 *ConfigData,
714   IN UINT8                              *ImageBuffer,
715   IN UINTN                              ImageSize,
716   IN EFI_FV_FILETYPE                    FileType,
717   IN EFI_FV_FILE_ATTRIBUTES             FileAttributes
718   )
719 {
720   EFI_STATUS                            Status;
721   EFI_FIRMWARE_VOLUME2_PROTOCOL          *FwVolProtocol;
722   EFI_FV_WRITE_FILE_DATA                FileData;
723   CHAR16                                *TmpStr;
724 
725   if (ConfigData->UpdateType != UpdateFvFile) {
726     return EFI_INVALID_PARAMETER;
727   }
728 
729   //
730   // Print on screen
731   //
732   TmpStr  = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL);
733   if (TmpStr != NULL) {
734     Print (TmpStr, &(ConfigData->FileGuid));
735     FreePool (TmpStr);
736   }
737 
738   DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n",
739     &(ConfigData->FileGuid)));
740 
741   //
742   // Get Firmware volume protocol on this FVB protocol
743   //
744   Status                = gBS->HandleProtocol (
745                                   FvbHandle,
746                                   &gEfiFirmwareVolume2ProtocolGuid,
747                                   (VOID **) &FwVolProtocol
748                                   );
749   if (EFI_ERROR (Status)) {
750     return Status;
751   }
752 
753   //
754   // If it is a PEIM, we need first to rebase it before committing
755   // the write to target
756   //
757   if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM )
758     || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {
759     return EFI_UNSUPPORTED;
760   }
761 
762   FileData.NameGuid         = &(ConfigData->FileGuid);
763   FileData.Type             = FileType;
764   FileData.FileAttributes   = FileAttributes;
765   FileData.Buffer           = ImageBuffer;
766   FileData.BufferSize       = (UINT32) ImageSize;
767 
768   Status                    = FwVolProtocol->WriteFile (
769                                                 FwVolProtocol,
770                                                 1,                        // NumberOfFiles
771                                                 (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant,
772                                                 &FileData
773                                                 );
774   return Status;
775 }
776 
777 /**
778   Update the buffer into flash area in fault tolerant write method.
779 
780   @param ImageBuffer     Image buffer to be updated.
781   @param SizeLeft        Size of the image buffer.
782   @param UpdatedSize     Size of the updated buffer.
783   @param ConfigData      Config data on updating driver.
784   @param FlashAddress    Flash address to be updated as start address.
785   @param FvbProtocol     FVB protocol.
786   @param FvbHandle       Handle of FVB protocol for the updated flash range.
787 
788   @retval EFI_SUCCESS            Buffer data is updated into flash.
789   @retval EFI_INVALID_PARAMETER  Base flash address is not in FVB flash area.
790   @retval EFI_NOT_FOUND          FTW protocol doesn't exist.
791   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
792   @retval EFI_ABORTED            Error happen when update flash area.
793 
794 **/
795 EFI_STATUS
FaultTolerantUpdateOnPartFv(IN UINT8 * ImageBuffer,IN UINTN SizeLeft,IN OUT UINTN * UpdatedSize,IN UPDATE_CONFIG_DATA * ConfigData,IN EFI_PHYSICAL_ADDRESS FlashAddress,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_HANDLE FvbHandle)796 FaultTolerantUpdateOnPartFv (
797   IN       UINT8                         *ImageBuffer,
798   IN       UINTN                         SizeLeft,
799   IN OUT   UINTN                         *UpdatedSize,
800   IN       UPDATE_CONFIG_DATA            *ConfigData,
801   IN       EFI_PHYSICAL_ADDRESS          FlashAddress,
802   IN       EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
803   IN       EFI_HANDLE                    FvbHandle
804   )
805 {
806   EFI_STATUS                            Status;
807   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
808   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeaderTmp;
809   EFI_PHYSICAL_ADDRESS                  BaseAddress;
810   EFI_PHYSICAL_ADDRESS                  FvBase;
811   EFI_PHYSICAL_ADDRESS                  NextBlock;
812   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
813   EFI_FV_BLOCK_MAP_ENTRY                *PtrMap;
814   UINTN                                 NumOfUpdates;
815   UINTN                                 TotalSize;
816   EFI_PHYSICAL_ADDRESS                  StartAddress;
817   EFI_FAULT_TOLERANT_WRITE_PROTOCOL     *FtwProtocol;
818   UINTN                                 MaxBlockSize;
819   UINTN                                 FtwMaxBlockSize;
820   BOOLEAN                               Pending;
821   UPDATE_PRIVATE_DATA                   PrivateData;
822   EFI_LBA                               PendingLba;
823   EFI_LBA                               Lba;
824   UINTN                                 BlockSize;
825   UINTN                                 PendingOffset;
826   UINTN                                 Offset;
827   UINTN                                 PendingLength;
828   UINTN                                 Length;
829   UINTN                                 Index;
830   UINT8                                 *Image;
831 
832   //
833   // Get the block map to update the block one by one
834   //
835   Status = FvbProtocol->GetPhysicalAddress (
836                           FvbProtocol,
837                           &FvBase
838                           );
839   if (EFI_ERROR (Status)) {
840     return Status;
841   }
842 
843   FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
844   if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) {
845     return EFI_INVALID_PARAMETER;
846   }
847 
848   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
849                                                 FwVolHeaderTmp->HeaderLength,
850                                                 FwVolHeaderTmp
851                                                 );
852   if (FwVolHeader == NULL) {
853     return EFI_OUT_OF_RESOURCES;
854   }
855 
856   //
857   // For fault tolerant write, we have to know how many blocks we need to
858   // update. So we will calculate number of updates and max block size first
859   //
860   NumOfUpdates          = 0;
861   MaxBlockSize          = 0;
862   TotalSize             = SizeLeft;
863   StartAddress          = FlashAddress;
864   BaseAddress           = FvBase;
865   BlockMap              = &(FwVolHeader->BlockMap[0]);
866   PtrMap                = BlockMap;
867 
868   while (TotalSize > 0) {
869     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
870       break;
871     }
872 
873     BlockSize           = PtrMap->Length;
874     for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
875       NextBlock         = BaseAddress + BlockSize;
876       //
877       // Check if this block need to be updated
878       //
879       if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
880         //
881         // Get the maximum block size
882         //
883         if (MaxBlockSize < BlockSize) {
884           MaxBlockSize  = BlockSize;
885         }
886 
887         //
888         // This block shall be udpated. So increment number of updates
889         //
890         NumOfUpdates++;
891         Offset          = (UINTN) (StartAddress - BaseAddress);
892         Length          = TotalSize;
893         if ((Length + Offset ) > BlockSize) {
894           Length        = BlockSize - Offset;
895         }
896 
897         StartAddress    = StartAddress + Length;
898         TotalSize       = TotalSize - Length;
899         if (TotalSize <= 0) {
900           break;
901         }
902       }
903       BaseAddress       = NextBlock;
904     }
905     PtrMap++;
906   }
907 
908   //
909   // Get the FTW protocol
910   //
911   Status = gBS->LocateProtocol (
912                   &gEfiFaultTolerantWriteProtocolGuid,
913                   NULL,
914                   (VOID **) &FtwProtocol
915                   );
916   if (EFI_ERROR (Status)) {
917     FreePool (FwVolHeader);
918     return EFI_NOT_FOUND;
919   }
920 
921   FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
922 
923   //
924   // Not enough backup space. return directly
925   //
926   if (FtwMaxBlockSize < MaxBlockSize) {
927     FreePool (FwVolHeader);
928     return EFI_OUT_OF_RESOURCES;
929   }
930 
931   PendingLba            = 0;
932   PendingOffset         = 0;
933   PendingLength         = 0;
934   Pending               = FALSE;
935 
936   //
937   // Fault Tolerant Write can only support actual fault tolerance if the write
938   // is a reclaim operation, which means the data buffer (new and old) are
939   // acutally both stored in flash. But for component update write, the data
940   // are now in memory. So we cannot actually recover the data after power
941   // failure.
942   //
943   Status = RetrieveLastWrite (
944              FvbHandle,
945              FtwProtocol,
946              ConfigData,
947              sizeof (UPDATE_PRIVATE_DATA),
948              &PrivateData,
949              &PendingLba,
950              &PendingOffset,
951              &PendingLength,
952              &Pending
953              );
954   if (Pending && (Status == EFI_NOT_FOUND)) {
955     //
956     // I'm not the owner of the pending fault tolerant write record
957     // Cannot continue with the write operation
958     //
959     FreePool (FwVolHeader);
960     return EFI_ABORTED;
961   }
962 
963   if (EFI_ERROR(Status)) {
964     FreePool (FwVolHeader);
965     return EFI_ABORTED;
966   }
967 
968   //
969   // Currently we start from the pending write if there is any. But if the
970   // caller is exactly the same, and the new data is already a in memory, (it
971   // cannot be stored in flash in last write,) we can just abort last write
972   // and start from the very begining.
973   //
974   if (!Pending) {
975     //
976     // Now allocte the update private data in FTW. If there is pending
977     // write, it has already been allocated and no need to allocate here.
978     //
979     Status = FtwProtocol->Allocate (
980                             FtwProtocol,
981                             &gEfiCallerIdGuid,
982                             sizeof (UPDATE_PRIVATE_DATA),
983                             NumOfUpdates
984                             );
985     if (EFI_ERROR (Status)) {
986       FreePool (FwVolHeader);
987       return Status;
988     }
989   }
990 
991   //
992   // Perform the update now. If there are pending writes, we need to
993   // start from the pending write instead of the very beginning.
994   //
995   TotalSize             = SizeLeft;
996   Lba                   = 0;
997   StartAddress          = FlashAddress;
998   BaseAddress           = FvBase;
999   PtrMap                = BlockMap;
1000   Image                 = ImageBuffer;
1001   CopyMem (
1002     (VOID *) &PrivateData.FileGuid,
1003     (VOID *) &ConfigData->FileGuid,
1004      sizeof (EFI_GUID)
1005   );
1006 
1007   while (TotalSize > 0) {
1008     if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
1009       break;
1010     }
1011 
1012     BlockSize           = (UINTN)PtrMap->Length;
1013     for (Index = 0;  Index < PtrMap->NumBlocks; Index++) {
1014       NextBlock         = BaseAddress + BlockSize;
1015       if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
1016         //
1017         // So we need to update this block
1018         //
1019         Offset          = (UINTN) (StartAddress - BaseAddress);
1020         Length          = TotalSize;
1021         if ((Length + Offset ) > BlockSize) {
1022           Length        = BlockSize - Offset;
1023         }
1024 
1025         //
1026         // Add an extra check here to see if the pending record is correct
1027         //
1028         if (Pending && (Lba == PendingLba)) {
1029           if ((PendingOffset != Offset) || (PendingLength != Length)) {
1030             //
1031             // Error.
1032             //
1033             Status          = EFI_ABORTED;
1034             break;
1035           }
1036         }
1037 
1038         if ((!Pending) || (Lba >= PendingLba)) {
1039           DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length));
1040           Status            = FtwProtocol->Write (
1041                                              FtwProtocol,
1042                                              Lba,                  // Lba
1043                                              Offset,               // Offset
1044                                              Length,               // Size
1045                                              &PrivateData,         // Private Data
1046                                              FvbHandle,            // FVB handle
1047                                              Image                 // Buffer
1048                                              );
1049           if (EFI_ERROR (Status)) {
1050             break;
1051           }
1052         }
1053 
1054         //
1055         // Now increment StartAddress, ImageBuffer and decrease the
1056         // left size to prepare for the next block update.
1057         //
1058         StartAddress    = StartAddress + Length;
1059         Image           = Image + Length;
1060         TotalSize       = TotalSize - Length;
1061         if (TotalSize <= 0) {
1062           break;
1063         }
1064       }
1065       BaseAddress       = NextBlock;
1066       Lba++;
1067     }
1068 
1069     if (EFI_ERROR (Status)) {
1070       break;
1071     }
1072     PtrMap++;
1073   }
1074 
1075   FreePool (FwVolHeader);
1076 
1077   *UpdatedSize = SizeLeft - TotalSize;
1078 
1079   return EFI_SUCCESS;
1080 }
1081 
1082 /**
1083   Directly update the buffer into flash area without fault tolerant write method.
1084 
1085   @param ImageBuffer     Image buffer to be updated.
1086   @param SizeLeft        Size of the image buffer.
1087   @param UpdatedSize     Size of the updated buffer.
1088   @param FlashAddress    Flash address to be updated as start address.
1089   @param FvbProtocol     FVB protocol.
1090   @param FvbHandle       Handle of FVB protocol for the updated flash range.
1091 
1092   @retval EFI_SUCCESS            Buffer data is updated into flash.
1093   @retval EFI_INVALID_PARAMETER  Base flash address is not in FVB flash area.
1094   @retval EFI_OUT_OF_RESOURCES   No enough backup space.
1095 
1096 **/
1097 EFI_STATUS
NonFaultTolerantUpdateOnPartFv(IN UINT8 * ImageBuffer,IN UINTN SizeLeft,IN OUT UINTN * UpdatedSize,IN EFI_PHYSICAL_ADDRESS FlashAddress,IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * FvbProtocol,IN EFI_HANDLE FvbHandle)1098 NonFaultTolerantUpdateOnPartFv (
1099   IN      UINT8                         *ImageBuffer,
1100   IN      UINTN                         SizeLeft,
1101   IN OUT  UINTN                         *UpdatedSize,
1102   IN      EFI_PHYSICAL_ADDRESS          FlashAddress,
1103   IN      EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
1104   IN      EFI_HANDLE                    FvbHandle
1105   )
1106 {
1107   EFI_STATUS                            Status;
1108   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
1109   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeaderTmp;
1110   EFI_PHYSICAL_ADDRESS                  BaseAddress;
1111   EFI_PHYSICAL_ADDRESS                  NextBlock;
1112   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
1113   UINTN                                 Index;
1114   UINTN                                 TotalSize;
1115   UINTN                                 BlockSize;
1116   EFI_LBA                               Lba;
1117   UINTN                                 Offset;
1118   UINTN                                 Length;
1119   UINT8                                 *Image;
1120 
1121   //
1122   // Get the block map to update the block one by one
1123   //
1124   Status                = FvbProtocol->GetPhysicalAddress (
1125                                          FvbProtocol,
1126                                          &BaseAddress
1127                                          );
1128   if (EFI_ERROR (Status)) {
1129     return Status;
1130   }
1131 
1132   FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
1133   if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) {
1134     return EFI_INVALID_PARAMETER;
1135   }
1136 
1137   FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
1138                                                 FwVolHeaderTmp->HeaderLength,
1139                                                 FwVolHeaderTmp
1140                                                 );
1141   if (FwVolHeader == NULL) {
1142     return EFI_OUT_OF_RESOURCES;
1143   }
1144 
1145   Image                 = ImageBuffer;
1146   TotalSize             = SizeLeft;
1147   BlockMap              = &(FwVolHeader->BlockMap[0]);
1148   Lba                   = 0;
1149 
1150   while (TotalSize > 0) {
1151     if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) {
1152       break;
1153     }
1154 
1155     BlockSize           = BlockMap->Length;
1156     for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) {
1157       NextBlock         = BaseAddress + BlockSize;
1158       if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) {
1159         //
1160         // So we need to update this block
1161         //
1162         Offset          = (UINTN) FlashAddress - (UINTN) BaseAddress;
1163         Length          = TotalSize;
1164         if ((Length + Offset ) > BlockSize) {
1165           Length        = BlockSize - Offset;
1166         }
1167 
1168         DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length));
1169         //
1170         // Update the block
1171         //
1172         Status          = UpdateBufferInOneBlock (
1173                             FvbProtocol,
1174                             Lba,
1175                             Offset,
1176                             Length,
1177                             BlockSize,
1178                             Image
1179                             );
1180         if (EFI_ERROR (Status)) {
1181           FreePool (FwVolHeader);
1182           return Status;
1183         }
1184 
1185         //
1186         // Now increment FlashAddress, ImageBuffer and decrease the
1187         // left size to prepare for the next block update.
1188         //
1189         FlashAddress    = FlashAddress + Length;
1190         Image           = Image + Length;
1191         TotalSize       = TotalSize - Length;
1192         if (TotalSize <= 0) {
1193           break;
1194         }
1195       }
1196       BaseAddress       = NextBlock;
1197       Lba++;
1198     }
1199 
1200     if (EFI_ERROR (Status)) {
1201       break;
1202     }
1203     BlockMap++;
1204   }
1205 
1206   FreePool (FwVolHeader);
1207 
1208   *UpdatedSize          = SizeLeft - TotalSize;
1209 
1210   return EFI_SUCCESS;
1211 }
1212