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