fixed one bug when copy MAC address.
[edk2.git] / DuetPkg / FvbRuntimeService / FWBlockService.c
blob664a4cffc6e9b38253012c05e661f5de07bd3c4f
1 /**@file
2 Copyright (c) 2007, Intel Corporation
3 All rights reserved. This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 Module Name:
13 FWBlockService.c
15 Abstract:
17 Revision History
19 **/
20 #include "FWBlockService.h"
21 #include "EfiFlashMap.h"
22 #include "FileIo.h"
23 #include "FlashLayout.h"
25 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
26 VOID *mSFSRegistration;
27 #define TRY_ASSIGN(var, value) if(var != NULL) {*var = value;}
29 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
30 FVB_DEVICE_SIGNATURE,
34 HARDWARE_DEVICE_PATH,
35 HW_MEMMAP_DP,
37 sizeof (MEMMAP_DEVICE_PATH),
41 EfiMemoryMappedIO,
46 END_DEVICE_PATH_TYPE,
47 END_ENTIRE_DEVICE_PATH_SUBTYPE,
49 sizeof (EFI_DEVICE_PATH_PROTOCOL),
56 FvbProtocolGetAttributes,
57 FvbProtocolSetAttributes,
58 FvbProtocolGetPhysicalAddress,
59 FvbProtocolGetBlockSize,
60 FvbProtocolRead,
61 FvbProtocolWrite,
62 FvbProtocolEraseBlocks,
63 NULL
68 EFI_STATUS
69 FlashFdWrite (
70 IN UINTN Address,
71 IN EFI_FW_VOL_INSTANCE *FwhInstance,
72 IN OUT UINTN *NumBytes,
73 IN UINT8 *Buffer
75 /*++
77 Routine Description:
78 Writes specified number of bytes from the input buffer to the address
80 Arguments:
82 Returns:
84 --*/
86 EFI_STATUS Status;
87 EFI_FILE *File;
88 UINTN FileOffset;
89 UINTN BufferForFile;
90 UINTN Length;
92 Status = EFI_SUCCESS;
93 CopyMem ((VOID *) Address, Buffer, *NumBytes);
95 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
96 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
97 ASSERT_EFI_ERROR (Status);
98 if (!EFI_ERROR (Status)) {
99 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
100 FileOffset = 0;
101 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
102 Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
103 } else {
104 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
105 BufferForFile = Address;
106 Length = *NumBytes;
109 Status = FileWrite (File, FileOffset, BufferForFile, Length);
110 ASSERT_EFI_ERROR (Status);
111 FileClose (File);
114 return Status;
117 EFI_STATUS
118 FlashFdErase (
119 IN UINTN Address,
120 IN EFI_FW_VOL_INSTANCE *FwhInstance,
121 IN UINTN LbaLength
123 /*++
125 Routine Description:
126 Erase a certain block from address LbaWriteAddress
128 Arguments:
130 Returns:
132 --*/
134 EFI_STATUS Status;
135 EFI_FILE *File;
136 UINTN FileOffset;
137 UINTN BufferForFile;
138 UINTN Length;
140 Status = EFI_SUCCESS;
142 SetMem ((VOID *)Address, LbaLength, 0xff);
144 if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
145 Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
146 ASSERT_EFI_ERROR (Status);
147 if (!EFI_ERROR (Status)) {
148 if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
149 FileOffset = 0;
150 BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
151 Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
152 } else {
153 FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
154 BufferForFile = Address;
155 Length = LbaLength;
158 Status = FileWrite (File, FileOffset, BufferForFile, Length);
159 ASSERT_EFI_ERROR (Status);
160 FileClose (File);
163 return Status;
166 VOID
167 EFIAPI
168 FvbVirtualddressChangeEvent (
169 IN EFI_EVENT Event,
170 IN VOID *Context
172 /*++
174 Routine Description:
176 Fixup internal data so that EFI and SAL can be call in virtual mode.
177 Call the passed in Child Notify event and convert the mFvbModuleGlobal
178 date items to there virtual address.
180 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
181 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
182 instance data.
184 Arguments:
186 (Standard EFI notify event - EFI_EVENT_NOTIFY)
188 Returns:
190 None
192 --*/
194 EFI_FW_VOL_INSTANCE *FwhInstance;
195 UINTN Index;
197 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
200 // Convert the base address of all the instances
202 Index = 0;
203 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
204 while (Index < mFvbModuleGlobal->NumFv) {
205 EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
206 FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength
207 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
208 Index++;
211 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
212 EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal);
215 EFI_STATUS
216 GetFvbInstance (
217 IN UINTN Instance,
218 IN ESAL_FWB_GLOBAL *Global,
219 OUT EFI_FW_VOL_INSTANCE **FwhInstance,
220 IN BOOLEAN Virtual
222 /*++
224 Routine Description:
225 Retrieves the physical address of a memory mapped FV
227 Arguments:
228 Instance - The FV instance whose base address is going to be
229 returned
230 Global - Pointer to ESAL_FWB_GLOBAL that contains all
231 instance data
232 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
233 Virtual - Whether CPU is in virtual or physical mode
235 Returns:
236 EFI_SUCCESS - Successfully returns
237 EFI_INVALID_PARAMETER - Instance not found
239 --*/
241 EFI_FW_VOL_INSTANCE *FwhRecord;
243 if (Instance >= Global->NumFv) {
244 return EFI_INVALID_PARAMETER;
247 // Find the right instance of the FVB private data
249 FwhRecord = Global->FvInstance[Virtual];
250 while (Instance > 0) {
251 FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength
252 + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
253 Instance--;
256 *FwhInstance = FwhRecord;
258 return EFI_SUCCESS;
261 EFI_STATUS
262 FvbGetPhysicalAddress (
263 IN UINTN Instance,
264 OUT EFI_PHYSICAL_ADDRESS *Address,
265 IN ESAL_FWB_GLOBAL *Global,
266 IN BOOLEAN Virtual
268 /*++
270 Routine Description:
271 Retrieves the physical address of a memory mapped FV
273 Arguments:
274 Instance - The FV instance whose base address is going to be
275 returned
276 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
277 that on successful return, contains the base address
278 of the firmware volume.
279 Global - Pointer to ESAL_FWB_GLOBAL that contains all
280 instance data
281 Virtual - Whether CPU is in virtual or physical mode
283 Returns:
284 EFI_SUCCESS - Successfully returns
285 EFI_INVALID_PARAMETER - Instance not found
287 --*/
289 EFI_FW_VOL_INSTANCE *FwhInstance;
290 EFI_STATUS Status;
293 // Find the right instance of the FVB private data
295 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
296 ASSERT_EFI_ERROR (Status);
297 *Address = FwhInstance->FvBase[Virtual];
299 return EFI_SUCCESS;
302 EFI_STATUS
303 FvbGetVolumeAttributes (
304 IN UINTN Instance,
305 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
306 IN ESAL_FWB_GLOBAL *Global,
307 IN BOOLEAN Virtual
309 /*++
311 Routine Description:
312 Retrieves attributes, insures positive polarity of attribute bits, returns
313 resulting attributes in output parameter
315 Arguments:
316 Instance - The FV instance whose attributes is going to be
317 returned
318 Attributes - Output buffer which contains attributes
319 Global - Pointer to ESAL_FWB_GLOBAL that contains all
320 instance data
321 Virtual - Whether CPU is in virtual or physical mode
323 Returns:
324 EFI_SUCCESS - Successfully returns
325 EFI_INVALID_PARAMETER - Instance not found
327 --*/
329 EFI_FW_VOL_INSTANCE *FwhInstance;
330 EFI_STATUS Status;
333 // Find the right instance of the FVB private data
335 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
336 ASSERT_EFI_ERROR (Status);
337 *Attributes = FwhInstance->VolumeHeader.Attributes;
339 return EFI_SUCCESS;
342 EFI_STATUS
343 FvbGetLbaAddress (
344 IN UINTN Instance,
345 IN EFI_LBA Lba,
346 OUT UINTN *LbaAddress OPTIONAL,
347 OUT UINTN *LbaLength OPTIONAL,
348 OUT UINTN *NumOfBlocks OPTIONAL,
349 IN ESAL_FWB_GLOBAL *Global,
350 IN BOOLEAN Virtual
352 /*++
354 Routine Description:
355 Retrieves the starting address of an LBA in an FV
357 Arguments:
358 Instance - The FV instance which the Lba belongs to
359 Lba - The logical block address
360 LbaAddress - On output, contains the physical starting address
361 of the Lba for writing
362 LbaLength - On output, contains the length of the block
363 NumOfBlocks - A pointer to a caller allocated UINTN in which the
364 number of consecutive blocks starting with Lba is
365 returned. All blocks in this range have a size of
366 BlockSize
367 Global - Pointer to ESAL_FWB_GLOBAL that contains all
368 instance data
369 Virtual - Whether CPU is in virtual or physical mode
371 Returns:
372 EFI_SUCCESS - Successfully returns
373 EFI_INVALID_PARAMETER - Instance not found
375 --*/
377 UINT32 NumBlocks;
378 UINT32 BlockLength;
379 UINTN Offset;
380 EFI_LBA StartLba;
381 EFI_LBA NextLba;
382 EFI_FW_VOL_INSTANCE *FwhInstance;
383 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
384 EFI_STATUS Status;
387 // Find the right instance of the FVB private data
389 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
390 ASSERT_EFI_ERROR (Status);
392 StartLba = 0;
393 Offset = 0;
394 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
397 // Parse the blockmap of the FV to find which map entry the Lba belongs to
399 while (TRUE) {
400 NumBlocks = BlockMap->NumBlocks;
401 BlockLength = BlockMap->Length;
403 if (NumBlocks == 0 || BlockLength == 0) {
404 return EFI_INVALID_PARAMETER;
407 NextLba = StartLba + NumBlocks;
410 // The map entry found
412 if (Lba >= StartLba && Lba < NextLba) {
413 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
415 if (LbaAddress) {
416 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
419 if (LbaLength) {
420 *LbaLength = BlockLength;
423 if (NumOfBlocks) {
424 *NumOfBlocks = (UINTN) (NextLba - Lba);
427 return EFI_SUCCESS;
430 StartLba = NextLba;
431 Offset = Offset + NumBlocks * BlockLength;
432 BlockMap++;
436 EFI_STATUS
437 FvbReadBlock (
438 IN UINTN Instance,
439 IN EFI_LBA Lba,
440 IN UINTN BlockOffset,
441 IN OUT UINTN *NumBytes,
442 IN UINT8 *Buffer,
443 IN ESAL_FWB_GLOBAL *Global,
444 IN BOOLEAN Virtual
446 /*++
448 Routine Description:
449 Reads specified number of bytes into a buffer from the specified block
451 Arguments:
452 Instance - The FV instance to be read from
453 Lba - The logical block address to be read from
454 BlockOffset - Offset into the block at which to begin reading
455 NumBytes - Pointer that on input contains the total size of
456 the buffer. On output, it contains the total number
457 of bytes read
458 Buffer - Pointer to a caller allocated buffer that will be
459 used to hold the data read
460 Global - Pointer to ESAL_FWB_GLOBAL that contains all
461 instance data
462 Virtual - Whether CPU is in virtual or physical mode
464 Returns:
465 EFI_SUCCESS - The firmware volume was read successfully and
466 contents are in Buffer
467 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
468 NumBytes contains the total number of bytes returned
469 in Buffer
470 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
471 EFI_DEVICE_ERROR - The block device is not functioning correctly and
472 could not be read
473 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
475 --*/
477 EFI_FVB_ATTRIBUTES_2 Attributes;
478 UINTN LbaAddress;
479 UINTN LbaLength;
480 EFI_STATUS Status;
483 // Check for invalid conditions
485 if ((NumBytes == NULL) || (Buffer == NULL)) {
486 return EFI_INVALID_PARAMETER;
489 if (*NumBytes == 0) {
490 return EFI_INVALID_PARAMETER;
493 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
494 if (EFI_ERROR (Status)) {
495 return Status;
498 // Check if the FV is read enabled
500 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
502 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
503 return EFI_ACCESS_DENIED;
506 // Perform boundary checks and adjust NumBytes
508 if (BlockOffset > LbaLength) {
509 return EFI_INVALID_PARAMETER;
512 if (LbaLength < (*NumBytes + BlockOffset)) {
513 *NumBytes = (UINT32) (LbaLength - BlockOffset);
514 Status = EFI_BAD_BUFFER_SIZE;
517 CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes);
519 return Status;
521 EFI_STATUS
522 FvbWriteBlock (
523 IN UINTN Instance,
524 IN EFI_LBA Lba,
525 IN UINTN BlockOffset,
526 IN OUT UINTN *NumBytes,
527 IN UINT8 *Buffer,
528 IN ESAL_FWB_GLOBAL *Global,
529 IN BOOLEAN Virtual
531 /*++
533 Routine Description:
534 Writes specified number of bytes from the input buffer to the block
536 Arguments:
537 Instance - The FV instance to be written to
538 Lba - The starting logical block index to write to
539 BlockOffset - Offset into the block at which to begin writing
540 NumBytes - Pointer that on input contains the total size of
541 the buffer. On output, it contains the total number
542 of bytes actually written
543 Buffer - Pointer to a caller allocated buffer that contains
544 the source for the write
545 Global - Pointer to ESAL_FWB_GLOBAL that contains all
546 instance data
547 Virtual - Whether CPU is in virtual or physical mode
549 Returns:
550 EFI_SUCCESS - The firmware volume was written successfully
551 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
552 NumBytes contains the total number of bytes
553 actually written
554 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
555 EFI_DEVICE_ERROR - The block device is not functioning correctly and
556 could not be written
557 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
559 --*/
561 EFI_FVB_ATTRIBUTES_2 Attributes;
562 UINTN LbaAddress;
563 UINTN LbaLength;
564 EFI_FW_VOL_INSTANCE *FwhInstance;
565 EFI_STATUS Status;
566 EFI_STATUS ReturnStatus;
569 // Find the right instance of the FVB private data
571 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
572 ASSERT_EFI_ERROR (Status);
575 // Writes are enabled in the init routine itself
577 if (!FwhInstance->WriteEnabled) {
578 return EFI_ACCESS_DENIED;
581 // Check for invalid conditions
583 if ((NumBytes == NULL) || (Buffer == NULL)) {
584 return EFI_INVALID_PARAMETER;
587 if (*NumBytes == 0) {
588 return EFI_INVALID_PARAMETER;
591 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
592 if (EFI_ERROR (Status)) {
593 return Status;
596 // Check if the FV is write enabled
598 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
600 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
601 return EFI_ACCESS_DENIED;
604 // Perform boundary checks and adjust NumBytes
606 if (BlockOffset > LbaLength) {
607 return EFI_INVALID_PARAMETER;
610 if (LbaLength < (*NumBytes + BlockOffset)) {
611 *NumBytes = (UINT32) (LbaLength - BlockOffset);
612 Status = EFI_BAD_BUFFER_SIZE;
615 ReturnStatus = FlashFdWrite (
616 LbaAddress + BlockOffset,
617 FwhInstance,
618 NumBytes,
619 Buffer
621 if (EFI_ERROR (ReturnStatus)) {
622 return ReturnStatus;
625 return Status;
628 EFI_STATUS
629 FvbEraseBlock (
630 IN UINTN Instance,
631 IN EFI_LBA Lba,
632 IN ESAL_FWB_GLOBAL *Global,
633 IN BOOLEAN Virtual
635 /*++
637 Routine Description:
638 Erases and initializes a firmware volume block
640 Arguments:
641 Instance - The FV instance to be erased
642 Lba - The logical block index to be erased
643 Global - Pointer to ESAL_FWB_GLOBAL that contains all
644 instance data
645 Virtual - Whether CPU is in virtual or physical mode
647 Returns:
648 EFI_SUCCESS - The erase request was successfully completed
649 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
650 EFI_DEVICE_ERROR - The block device is not functioning correctly and
651 could not be written. Firmware device may have been
652 partially erased
653 EFI_INVALID_PARAMETER - Instance not found
655 --*/
658 EFI_FVB_ATTRIBUTES_2 Attributes;
659 UINTN LbaAddress;
660 EFI_FW_VOL_INSTANCE *FwhInstance;
661 UINTN LbaLength;
662 EFI_STATUS Status;
665 // Find the right instance of the FVB private data
667 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
668 ASSERT_EFI_ERROR (Status);
671 // Writes are enabled in the init routine itself
673 if (!FwhInstance->WriteEnabled) {
674 return EFI_ACCESS_DENIED;
677 // Check if the FV is write enabled
679 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
681 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
682 return EFI_ACCESS_DENIED;
685 // Get the starting address of the block for erase. For debug reasons,
686 // LbaWriteAddress may not be the same as LbaAddress.
688 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
689 if (EFI_ERROR (Status)) {
690 return Status;
693 return FlashFdErase (
694 LbaAddress,
695 FwhInstance,
696 LbaLength
700 EFI_STATUS
701 FvbSetVolumeAttributes (
702 IN UINTN Instance,
703 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
704 IN ESAL_FWB_GLOBAL *Global,
705 IN BOOLEAN Virtual
707 /*++
709 Routine Description:
710 Modifies the current settings of the firmware volume according to the
711 input parameter, and returns the new setting of the volume
713 Arguments:
714 Instance - The FV instance whose attributes is going to be
715 modified
716 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
717 containing the desired firmware volume settings.
718 On successful return, it contains the new settings
719 of the firmware volume
720 Global - Pointer to ESAL_FWB_GLOBAL that contains all
721 instance data
722 Virtual - Whether CPU is in virtual or physical mode
724 Returns:
725 EFI_SUCCESS - Successfully returns
726 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
727 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
728 in conflict with the capabilities as declared in the
729 firmware volume header
731 --*/
733 EFI_FW_VOL_INSTANCE *FwhInstance;
734 EFI_FVB_ATTRIBUTES_2 OldAttributes;
735 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
736 UINT32 Capabilities;
737 UINT32 OldStatus;
738 UINT32 NewStatus;
739 EFI_STATUS Status;
742 // Find the right instance of the FVB private data
744 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
745 ASSERT_EFI_ERROR (Status);
747 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
748 OldAttributes = *AttribPtr;
749 Capabilities = OldAttributes & EFI_FVB2_CAPABILITIES;
750 OldStatus = OldAttributes & EFI_FVB2_STATUS;
751 NewStatus = *Attributes & EFI_FVB2_STATUS;
754 // If firmware volume is locked, no status bit can be updated
756 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
757 if (OldStatus ^ NewStatus) {
758 return EFI_ACCESS_DENIED;
762 // Test read disable
764 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
765 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
766 return EFI_INVALID_PARAMETER;
770 // Test read enable
772 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
773 if (NewStatus & EFI_FVB2_READ_STATUS) {
774 return EFI_INVALID_PARAMETER;
778 // Test write disable
780 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
781 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
782 return EFI_INVALID_PARAMETER;
786 // Test write enable
788 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
789 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
790 return EFI_INVALID_PARAMETER;
794 // Test lock
796 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
797 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
798 return EFI_INVALID_PARAMETER;
802 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
803 *AttribPtr = (*AttribPtr) | NewStatus;
804 *Attributes = *AttribPtr;
806 return EFI_SUCCESS;
809 // FVB protocol APIs
811 EFI_STATUS
812 EFIAPI
813 FvbProtocolGetPhysicalAddress (
814 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
815 OUT EFI_PHYSICAL_ADDRESS *Address
817 /*++
819 Routine Description:
821 Retrieves the physical address of the device.
823 Arguments:
825 This - Calling context
826 Address - Output buffer containing the address.
828 Returns:
830 Returns:
831 EFI_SUCCESS - Successfully returns
833 --*/
835 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
837 FvbDevice = FVB_DEVICE_FROM_THIS (This);
839 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
842 EFI_STATUS
843 EFIAPI
844 FvbProtocolGetBlockSize (
845 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
846 IN EFI_LBA Lba,
847 OUT UINTN *BlockSize,
848 OUT UINTN *NumOfBlocks
850 /*++
852 Routine Description:
853 Retrieve the size of a logical block
855 Arguments:
856 This - Calling context
857 Lba - Indicates which block to return the size for.
858 BlockSize - A pointer to a caller allocated UINTN in which
859 the size of the block is returned
860 NumOfBlocks - a pointer to a caller allocated UINTN in which the
861 number of consecutive blocks starting with Lba is
862 returned. All blocks in this range have a size of
863 BlockSize
865 Returns:
866 EFI_SUCCESS - The firmware volume was read successfully and
867 contents are in Buffer
869 --*/
871 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
873 FvbDevice = FVB_DEVICE_FROM_THIS (This);
875 return FvbGetLbaAddress (
876 FvbDevice->Instance,
877 Lba,
878 NULL,
879 BlockSize,
880 NumOfBlocks,
881 mFvbModuleGlobal,
882 EfiGoneVirtual ()
886 EFI_STATUS
887 EFIAPI
888 FvbProtocolGetAttributes (
889 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
890 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
892 /*++
894 Routine Description:
895 Retrieves Volume attributes. No polarity translations are done.
897 Arguments:
898 This - Calling context
899 Attributes - output buffer which contains attributes
901 Returns:
902 EFI_SUCCESS - Successfully returns
904 --*/
906 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
908 FvbDevice = FVB_DEVICE_FROM_THIS (This);
910 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
913 EFI_STATUS
914 EFIAPI
915 FvbProtocolSetAttributes (
916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
917 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
919 /*++
921 Routine Description:
922 Sets Volume attributes. No polarity translations are done.
924 Arguments:
925 This - Calling context
926 Attributes - output buffer which contains attributes
928 Returns:
929 EFI_SUCCESS - Successfully returns
931 --*/
933 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
935 FvbDevice = FVB_DEVICE_FROM_THIS (This);
937 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
940 EFI_STATUS
941 EFIAPI
942 FvbProtocolEraseBlocks (
943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
944 ...
946 /*++
948 Routine Description:
950 The EraseBlock() function erases one or more blocks as denoted by the
951 variable argument list. The entire parameter list of blocks must be verified
952 prior to erasing any blocks. If a block is requested that does not exist
953 within the associated firmware volume (it has a larger index than the last
954 block of the firmware volume), the EraseBlock() function must return
955 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
957 Arguments:
958 This - Calling context
959 ... - Starting LBA followed by Number of Lba to erase.
960 a -1 to terminate the list.
962 Returns:
963 EFI_SUCCESS - The erase request was successfully completed
964 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
965 EFI_DEVICE_ERROR - The block device is not functioning correctly and
966 could not be written. Firmware device may have been
967 partially erased
969 --*/
971 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
972 EFI_FW_VOL_INSTANCE *FwhInstance;
973 UINTN NumOfBlocks;
974 VA_LIST args;
975 EFI_LBA StartingLba;
976 UINTN NumOfLba;
977 EFI_STATUS Status;
979 FvbDevice = FVB_DEVICE_FROM_THIS (This);
981 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
982 ASSERT_EFI_ERROR (Status);
984 NumOfBlocks = FwhInstance->NumOfBlocks;
986 VA_START (args, This);
988 do {
989 StartingLba = VA_ARG (args, EFI_LBA);
990 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
991 break;
994 NumOfLba = VA_ARG (args, UINT32);
997 // Check input parameters
999 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
1000 VA_END (args);
1001 return EFI_INVALID_PARAMETER;
1003 } while (1);
1005 VA_END (args);
1007 VA_START (args, This);
1008 do {
1009 StartingLba = VA_ARG (args, EFI_LBA);
1010 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1011 break;
1014 NumOfLba = VA_ARG (args, UINT32);
1016 while (NumOfLba > 0) {
1017 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
1018 if (EFI_ERROR (Status)) {
1019 VA_END (args);
1020 return Status;
1023 StartingLba++;
1024 NumOfLba--;
1027 } while (1);
1029 VA_END (args);
1031 return EFI_SUCCESS;
1034 EFI_STATUS
1035 EFIAPI
1036 FvbProtocolWrite (
1037 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1038 IN EFI_LBA Lba,
1039 IN UINTN Offset,
1040 IN OUT UINTN *NumBytes,
1041 IN UINT8 *Buffer
1043 /*++
1045 Routine Description:
1047 Writes data beginning at Lba:Offset from FV. The write terminates either
1048 when *NumBytes of data have been written, or when a block boundary is
1049 reached. *NumBytes is updated to reflect the actual number of bytes
1050 written. The write opertion does not include erase. This routine will
1051 attempt to write only the specified bytes. If the writes do not stick,
1052 it will return an error.
1054 Arguments:
1055 This - Calling context
1056 Lba - Block in which to begin write
1057 Offset - Offset in the block at which to begin write
1058 NumBytes - On input, indicates the requested write size. On
1059 output, indicates the actual number of bytes written
1060 Buffer - Buffer containing source data for the write.
1062 Returns:
1063 EFI_SUCCESS - The firmware volume was written successfully
1064 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1065 NumBytes contains the total number of bytes
1066 actually written
1067 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1068 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1069 could not be written
1070 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1072 --*/
1075 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1077 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1079 return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1082 EFI_STATUS
1083 EFIAPI
1084 FvbProtocolRead (
1085 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1086 IN EFI_LBA Lba,
1087 IN UINTN Offset,
1088 IN OUT UINTN *NumBytes,
1089 IN UINT8 *Buffer
1091 /*++
1093 Routine Description:
1095 Reads data beginning at Lba:Offset from FV. The Read terminates either
1096 when *NumBytes of data have been read, or when a block boundary is
1097 reached. *NumBytes is updated to reflect the actual number of bytes
1098 written. The write opertion does not include erase. This routine will
1099 attempt to write only the specified bytes. If the writes do not stick,
1100 it will return an error.
1102 Arguments:
1103 This - Calling context
1104 Lba - Block in which to begin Read
1105 Offset - Offset in the block at which to begin Read
1106 NumBytes - On input, indicates the requested write size. On
1107 output, indicates the actual number of bytes Read
1108 Buffer - Buffer containing source data for the Read.
1110 Returns:
1111 EFI_SUCCESS - The firmware volume was read successfully and
1112 contents are in Buffer
1113 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1114 NumBytes contains the total number of bytes returned
1115 in Buffer
1116 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1117 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1118 could not be read
1119 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1121 --*/
1124 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1126 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1128 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1131 EFI_STATUS
1132 ValidateFvHeader (
1133 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
1135 /*++
1137 Routine Description:
1138 Check the integrity of firmware volume header
1140 Arguments:
1141 FwVolHeader - A pointer to a firmware volume header
1143 Returns:
1144 EFI_SUCCESS - The firmware volume is consistent
1145 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1147 --*/
1149 UINT16 *Ptr;
1150 UINT16 HeaderLength;
1151 UINT16 Checksum;
1154 // Verify the header revision, header signature, length
1155 // Length of FvBlock cannot be 2**64-1
1156 // HeaderLength cannot be an odd number
1158 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1159 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1160 (FwVolHeader->FvLength == ((UINTN) -1)) ||
1161 ((FwVolHeader->HeaderLength & 0x01) != 0)
1163 return EFI_NOT_FOUND;
1166 // Verify the header checksum
1168 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);
1169 Ptr = (UINT16 *) FwVolHeader;
1170 Checksum = 0;
1171 while (HeaderLength > 0) {
1172 Checksum = Checksum + (*Ptr);
1173 HeaderLength--;
1174 Ptr++;
1177 if (Checksum != 0) {
1178 return EFI_NOT_FOUND;
1181 return EFI_SUCCESS;
1185 EFI_STATUS
1186 GetFvbHeader (
1187 IN OUT EFI_PEI_HOB_POINTERS *HobList,
1188 OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader,
1189 OUT EFI_PHYSICAL_ADDRESS *BaseAddress OPTIONAL,
1190 OUT UINT32 *VolumeId OPTIONAL,
1191 OUT CHAR16 **MappedFile OPTIONAL,
1192 OUT UINT32 *ActuralSize OPTIONAL,
1193 OUT UINT32 *Offset OPTIONAL,
1194 OUT BOOLEAN *WriteBack OPTIONAL
1197 EFI_STATUS Status;
1198 EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry;
1199 EFI_FLASH_SUBAREA_ENTRY *FlashMapSubEntry;
1201 Status = EFI_SUCCESS;
1202 *FwVolHeader = NULL;
1203 TRY_ASSIGN (WriteBack, FALSE);
1205 DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw));
1206 (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw);
1207 if ((*HobList).Raw == NULL) {
1208 return EFI_NOT_FOUND;
1211 FlashMapEntry = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid);
1212 FlashMapSubEntry = &FlashMapEntry->Entries[0];
1215 // Check if it is a "FVB" area
1217 if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {
1218 return Status;
1221 // Check if it is a "real" flash
1223 if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {
1224 return Status;
1227 TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base);
1230 // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver
1232 TRY_ASSIGN (VolumeId, FlashMapEntry->VolumeId);
1233 TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize);
1234 TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath));
1235 TRY_ASSIGN (Offset, FlashMapEntry->Offset);
1237 DEBUG ((
1238 EFI_D_INFO,
1239 "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n",
1240 (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length,
1241 (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset
1243 DEBUG ((
1244 EFI_D_INFO,
1245 "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",
1246 (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath
1248 *FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base);
1249 Status = ValidateFvHeader (*FwVolHeader);
1250 if (EFI_ERROR (Status)) {
1252 // Get FvbInfo
1254 TRY_ASSIGN (WriteBack, TRUE);
1255 Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader);
1256 DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));
1257 ASSERT_EFI_ERROR (Status);
1260 return EFI_SUCCESS;
1263 VOID
1264 EFIAPI
1265 OnSimpleFileSystemInstall (
1266 IN EFI_EVENT Event,
1267 IN VOID *Context
1270 EFI_STATUS Status;
1271 UINTN HandleSize;
1272 EFI_HANDLE Handle;
1273 UINTN Instance;
1274 EFI_DEVICE_PATH_PROTOCOL *Device;
1275 EFI_FILE *File;
1276 EFI_FW_VOL_INSTANCE *FwhInstance;
1277 while (TRUE) {
1278 HandleSize = sizeof (EFI_HANDLE);
1279 Status = gBS->LocateHandle (
1280 ByRegisterNotify,
1281 NULL,
1282 mSFSRegistration,
1283 &HandleSize,
1284 &Handle
1286 if (Status == EFI_NOT_FOUND) {
1287 break;
1289 DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n"));
1290 ASSERT_EFI_ERROR (Status);
1292 // Check if this is the storage we care about, and store it in FwhInstance
1294 for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) {
1295 Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE);
1296 ASSERT_EFI_ERROR (Status);
1298 if (FwhInstance->MappedFile[0] == L'\0') {
1300 // The instance of FVB isn't mapped to file.
1302 continue;
1305 if ((FwhInstance->Device != NULL) &&
1306 !EFI_ERROR (CheckStoreExists (FwhInstance->Device))
1309 // The instance of FVB has already associated to a device
1310 // and the device is not removed from system.
1312 DEBUG ((
1313 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n",
1314 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1315 (UINTN) FwhInstance->Offset
1317 continue;
1320 Status = CheckStore (Handle, FwhInstance->VolumeId, &Device);
1321 if (!EFI_ERROR (Status)) {
1323 // Write back memory content to file
1325 Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE);
1326 ASSERT_EFI_ERROR (Status);
1327 if (!EFI_ERROR (Status)) {
1328 DEBUG ((
1329 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n",
1330 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1331 (UINTN) FwhInstance->Offset
1333 Status = FileWrite (
1334 File,
1336 FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset,
1337 FwhInstance->ActuralSize - FwhInstance->Offset
1339 ASSERT_EFI_ERROR (Status);
1340 if (!EFI_ERROR (Status)) {
1341 if (FwhInstance->Device != NULL) {
1342 gBS->FreePool (FwhInstance->Device);
1344 FwhInstance->Device = Device;
1345 DEBUG ((
1346 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",
1347 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1348 (UINTN) FwhInstance->Offset
1351 FileClose (File);
1358 VOID
1359 FvbInstallSfsNotify (
1360 VOID
1363 EFI_STATUS Status;
1364 EFI_EVENT Event;
1366 Status = gBS->CreateEvent (
1367 EVT_NOTIFY_SIGNAL,
1368 TPL_CALLBACK,
1369 OnSimpleFileSystemInstall,
1370 NULL,
1371 &Event
1373 ASSERT_EFI_ERROR (Status);
1375 Status = gBS->RegisterProtocolNotify (
1376 &gEfiSimpleFileSystemProtocolGuid,
1377 Event,
1378 &mSFSRegistration
1380 ASSERT_EFI_ERROR (Status);
1384 EFI_STATUS
1385 EFIAPI
1386 FvbInitialize (
1387 IN EFI_HANDLE ImageHandle,
1388 IN EFI_SYSTEM_TABLE *SystemTable
1390 /*++
1392 Routine Description:
1393 This function does common initialization for FVB services
1395 Arguments:
1397 Returns:
1399 --*/
1401 EFI_STATUS Status;
1402 EFI_FW_VOL_INSTANCE *FwhInstance;
1403 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1404 EFI_PEI_HOB_POINTERS FirmwareVolumeHobList;
1405 UINT32 BufferSize;
1406 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1407 UINTN LbaAddress;
1408 EFI_HANDLE FwbHandle;
1409 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1410 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1411 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;
1412 FV_DEVICE_PATH TempFvbDevicePathData;
1413 UINT32 MaxLbaSize;
1414 EFI_PHYSICAL_ADDRESS BaseAddress;
1415 UINT32 VolumeId;
1416 CHAR16 *MappedFile;
1417 UINT32 ActuralSize;
1418 UINT32 Offset;
1419 BOOLEAN WriteBack;
1420 UINTN NumOfBlocks;
1421 UINTN HeaderLength;
1422 BOOLEAN InstallSfsNotify;
1424 HeaderLength = 0;
1425 InstallSfsNotify = FALSE;
1428 // Allocate runtime services data for global variable, which contains
1429 // the private data of all firmware volume block instances
1431 Status = gBS->AllocatePool (
1432 EfiRuntimeServicesData,
1433 sizeof (ESAL_FWB_GLOBAL),
1434 &mFvbModuleGlobal
1436 ASSERT_EFI_ERROR (Status);
1438 // Calculate the total size for all firmware volume block instances
1440 BufferSize = 0;
1441 FirmwareVolumeHobList.Raw = GetHobList();
1442 do {
1443 Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL);
1444 if (EFI_ERROR (Status)) {
1445 break;
1447 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
1449 if (FwVolHeader) {
1450 BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1452 } while (TRUE);
1455 // Only need to allocate once. There is only one copy of physical memory for
1456 // the private data of each FV instance. But in virtual mode or in physical
1457 // mode, the address of the the physical memory may be different.
1459 Status = gBS->AllocatePool (
1460 EfiRuntimeServicesData,
1461 BufferSize,
1462 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
1464 ASSERT_EFI_ERROR (Status);
1467 // Make a virtual copy of the FvInstance pointer.
1469 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1470 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1472 mFvbModuleGlobal->NumFv = 0;
1473 FirmwareVolumeHobList.Raw = GetHobList();
1474 MaxLbaSize = 0;
1477 // Fill in the private data of each firmware volume block instance
1479 do {
1480 Status = GetFvbHeader (
1481 &FirmwareVolumeHobList, &FwVolHeader,
1482 &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset,
1483 &WriteBack
1485 if (EFI_ERROR (Status)) {
1486 break;
1488 FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
1490 if (!FwVolHeader) {
1491 continue;
1494 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1495 FwVolHeader = &(FwhInstance->VolumeHeader);
1497 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1498 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1499 FwhInstance->Device = NULL;
1500 FwhInstance->Offset = Offset;
1502 if (*MappedFile != '\0') {
1503 FwhInstance->VolumeId = VolumeId;
1504 FwhInstance->ActuralSize = ActuralSize;
1505 StrCpy (FwhInstance->MappedFile, MappedFile);
1507 InstallSfsNotify = TRUE;
1508 } else {
1509 FwhInstance->VolumeId = (UINT32) -1;
1510 FwhInstance->ActuralSize = (UINT32) -1;
1511 FwhInstance->MappedFile[0] = L'\0';
1514 DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",
1515 (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize));
1517 // We may expose readonly FVB in future.
1519 FwhInstance->WriteEnabled = TRUE; // Ken: Why enable write?
1520 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1522 LbaAddress = (UINTN) FwhInstance->FvBase[0];
1523 NumOfBlocks = 0;
1525 if (FwhInstance->WriteEnabled) {
1526 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1528 LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length;
1530 // Get the maximum size of a block. The size will be used to allocate
1531 // buffer for Scratch space, the intermediate buffer for FVB extension
1532 // protocol
1534 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1535 MaxLbaSize = PtrBlockMapEntry->Length;
1538 NumOfBlocks += PtrBlockMapEntry->NumBlocks;
1541 // Write back a healthy FV header
1543 if (WriteBack) {
1544 Status = FlashFdErase (
1545 (UINTN) FwhInstance->FvBase[0],
1546 FwhInstance,
1547 FwVolHeader->BlockMap->Length
1550 HeaderLength = (UINTN) FwVolHeader->HeaderLength;
1552 Status = FlashFdWrite (
1553 (UINTN) FwhInstance->FvBase[0],
1554 FwhInstance,
1555 (UINTN *) &HeaderLength,
1556 (UINT8 *) FwVolHeader
1559 FwVolHeader->HeaderLength = (UINT16) HeaderLength;
1561 DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status));
1565 // The total number of blocks in the FV.
1567 FwhInstance->NumOfBlocks = NumOfBlocks;
1570 // Add a FVB Protocol Instance
1572 Status = gBS->AllocatePool (
1573 EfiRuntimeServicesData,
1574 sizeof (EFI_FW_VOL_BLOCK_DEVICE),
1575 &FvbDevice
1577 ASSERT_EFI_ERROR (Status);
1579 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1581 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1582 mFvbModuleGlobal->NumFv++;
1585 // Set up the devicepath
1587 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1588 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);
1591 // Find a handle with a matching device path that has supports FW Block protocol
1593 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1594 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1595 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1596 if (EFI_ERROR (Status)) {
1598 // LocateDevicePath fails so install a new interface and device path
1600 FwbHandle = NULL;
1601 Status = gBS->InstallMultipleProtocolInterfaces (
1602 &FwbHandle,
1603 &gEfiFirmwareVolumeBlockProtocolGuid,
1604 &FvbDevice->FwVolBlockInstance,
1605 &gEfiDevicePathProtocolGuid,
1606 &FvbDevice->DevicePath,
1607 NULL
1609 ASSERT_EFI_ERROR (Status);
1610 } else if (IsDevicePathEnd (TempFwbDevicePath)) {
1612 // Device allready exists, so reinstall the FVB protocol
1614 Status = gBS->HandleProtocol (
1615 FwbHandle,
1616 &gEfiFirmwareVolumeBlockProtocolGuid,
1617 &OldFwbInterface
1619 ASSERT_EFI_ERROR (Status);
1621 Status = gBS->ReinstallProtocolInterface (
1622 FwbHandle,
1623 &gEfiFirmwareVolumeBlockProtocolGuid,
1624 OldFwbInterface,
1625 &FvbDevice->FwVolBlockInstance
1627 ASSERT_EFI_ERROR (Status);
1629 } else {
1631 // There was a FVB protocol on an End Device Path node
1633 ASSERT (FALSE);
1636 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1638 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1639 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1641 } while (TRUE);
1644 // Allocate for scratch space, an intermediate buffer for FVB extention
1646 Status = gBS->AllocatePool (
1647 EfiRuntimeServicesData,
1648 MaxLbaSize,
1649 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]
1651 ASSERT_EFI_ERROR (Status);
1653 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
1655 if (InstallSfsNotify) {
1656 FvbInstallSfsNotify ();
1658 return EFI_SUCCESS;