]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
IntelFrameworkModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / FirmwareVolume / UpdateDriverDxe / FlashUpdate.c
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
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
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
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
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
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
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
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
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
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 }