]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
FatPkg: Clean up source files
[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 - 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
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
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
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
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
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
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
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
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
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 }