]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/FvbServicesRuntimeDxe/FWBlockService.c
MdeModulePkg PciBusDxe: Add typecast to eliminate possible "loss of precision" warning.
[mirror_edk2.git] / Nt32Pkg / FvbServicesRuntimeDxe / FWBlockService.c
1 /**@file
2
3 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 FWBlockService.c
15
16 Abstract:
17
18 Revision History
19
20 **/
21
22 //
23 // The package level header files this module uses
24 //
25 #include <PiDxe.h>
26 #include <WinNtDxe.h>
27 //
28 // The protocols, PPI and GUID defintions for this module
29 //
30 #include <Guid/EventGroup.h>
31 #include <Protocol/FirmwareVolumeBlock.h>
32 #include <Protocol/DevicePath.h>
33 //
34 // The Library classes this module consumes
35 //
36 #include <Library/UefiLib.h>
37 #include <Library/UefiDriverEntryPoint.h>
38 #include <Library/BaseLib.h>
39 #include <Library/DxeServicesTableLib.h>
40 #include <Library/UefiRuntimeLib.h>
41 #include <Library/DebugLib.h>
42 #include <Library/HobLib.h>
43 #include <Library/BaseMemoryLib.h>
44 #include <Library/MemoryAllocationLib.h>
45 #include <Library/UefiBootServicesTableLib.h>
46 #include <Library/DevicePathLib.h>
47
48 #include "FWBlockService.h"
49
50 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
51
52 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
53
54 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
55 {
56 {
57 HARDWARE_DEVICE_PATH,
58 HW_MEMMAP_DP,
59 {
60 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
61 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
62 }
63 },
64 EfiMemoryMappedIO,
65 (EFI_PHYSICAL_ADDRESS) 0,
66 (EFI_PHYSICAL_ADDRESS) 0,
67 },
68 {
69 END_DEVICE_PATH_TYPE,
70 END_ENTIRE_DEVICE_PATH_SUBTYPE,
71 {
72 END_DEVICE_PATH_LENGTH,
73 0
74 }
75 }
76 };
77
78 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
79 {
80 {
81 MEDIA_DEVICE_PATH,
82 MEDIA_PIWG_FW_VOL_DP,
83 {
84 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
85 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
86 }
87 },
88 { 0 }
89 },
90 {
91 END_DEVICE_PATH_TYPE,
92 END_ENTIRE_DEVICE_PATH_SUBTYPE,
93 {
94 END_DEVICE_PATH_LENGTH,
95 0
96 }
97 }
98 };
99
100 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
101 FVB_DEVICE_SIGNATURE,
102 NULL,
103 0,
104 {
105 FvbProtocolGetAttributes,
106 FvbProtocolSetAttributes,
107 FvbProtocolGetPhysicalAddress,
108 FvbProtocolGetBlockSize,
109 FvbProtocolRead,
110 FvbProtocolWrite,
111 FvbProtocolEraseBlocks,
112 NULL
113 }
114 };
115
116
117
118 VOID
119 EFIAPI
120 FvbVirtualddressChangeEvent (
121 IN EFI_EVENT Event,
122 IN VOID *Context
123 )
124 /*++
125
126 Routine Description:
127
128 Fixup internal data so that EFI and SAL can be call in virtual mode.
129 Call the passed in Child Notify event and convert the mFvbModuleGlobal
130 date items to there virtual address.
131
132 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
133 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
134 instance data.
135
136 Arguments:
137
138 (Standard EFI notify event - EFI_EVENT_NOTIFY)
139
140 Returns:
141
142 None
143
144 --*/
145 {
146 EFI_FW_VOL_INSTANCE *FwhInstance;
147 UINTN Index;
148
149 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
150
151 //
152 // Convert the base address of all the instances
153 //
154 Index = 0;
155 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
156 while (Index < mFvbModuleGlobal->NumFv) {
157 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
158 FwhInstance = (EFI_FW_VOL_INSTANCE *)
159 (
160 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
161 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
162 );
163 Index++;
164 }
165
166 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
167 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
168 }
169
170 EFI_STATUS
171 GetFvbInstance (
172 IN UINTN Instance,
173 IN ESAL_FWB_GLOBAL *Global,
174 OUT EFI_FW_VOL_INSTANCE **FwhInstance,
175 IN BOOLEAN Virtual
176 )
177 /*++
178
179 Routine Description:
180 Retrieves the physical address of a memory mapped FV
181
182 Arguments:
183 Instance - The FV instance whose base address is going to be
184 returned
185 Global - Pointer to ESAL_FWB_GLOBAL that contains all
186 instance data
187 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
188 Virtual - Whether CPU is in virtual or physical mode
189
190 Returns:
191 EFI_SUCCESS - Successfully returns
192 EFI_INVALID_PARAMETER - Instance not found
193
194 --*/
195 {
196 EFI_FW_VOL_INSTANCE *FwhRecord;
197
198 if (Instance >= Global->NumFv) {
199 return EFI_INVALID_PARAMETER;
200 }
201 //
202 // Find the right instance of the FVB private data
203 //
204 FwhRecord = Global->FvInstance[Virtual];
205 while (Instance > 0) {
206 FwhRecord = (EFI_FW_VOL_INSTANCE *)
207 (
208 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
209 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
210 );
211 Instance--;
212 }
213
214 *FwhInstance = FwhRecord;
215
216 return EFI_SUCCESS;
217 }
218
219 EFI_STATUS
220 FvbGetPhysicalAddress (
221 IN UINTN Instance,
222 OUT EFI_PHYSICAL_ADDRESS *Address,
223 IN ESAL_FWB_GLOBAL *Global,
224 IN BOOLEAN Virtual
225 )
226 /*++
227
228 Routine Description:
229 Retrieves the physical address of a memory mapped FV
230
231 Arguments:
232 Instance - The FV instance whose base address is going to be
233 returned
234 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
235 that on successful return, contains the base address
236 of the firmware volume.
237 Global - Pointer to ESAL_FWB_GLOBAL that contains all
238 instance data
239 Virtual - Whether CPU is in virtual or physical mode
240
241 Returns:
242 EFI_SUCCESS - Successfully returns
243 EFI_INVALID_PARAMETER - Instance not found
244
245 --*/
246 {
247 EFI_FW_VOL_INSTANCE *FwhInstance;
248 EFI_STATUS Status;
249
250 //
251 // Find the right instance of the FVB private data
252 //
253 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
254 ASSERT_EFI_ERROR (Status);
255 *Address = FwhInstance->FvBase[Virtual];
256
257 return EFI_SUCCESS;
258 }
259
260 EFI_STATUS
261 FvbGetVolumeAttributes (
262 IN UINTN Instance,
263 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
264 IN ESAL_FWB_GLOBAL *Global,
265 IN BOOLEAN Virtual
266 )
267 /*++
268
269 Routine Description:
270 Retrieves attributes, insures positive polarity of attribute bits, returns
271 resulting attributes in output parameter
272
273 Arguments:
274 Instance - The FV instance whose attributes is going to be
275 returned
276 Attributes - Output buffer which contains attributes
277 Global - Pointer to ESAL_FWB_GLOBAL that contains all
278 instance data
279 Virtual - Whether CPU is in virtual or physical mode
280
281 Returns:
282 EFI_SUCCESS - Successfully returns
283 EFI_INVALID_PARAMETER - Instance not found
284
285 --*/
286 {
287 EFI_FW_VOL_INSTANCE *FwhInstance;
288 EFI_STATUS Status;
289
290 //
291 // Find the right instance of the FVB private data
292 //
293 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
294 ASSERT_EFI_ERROR (Status);
295 *Attributes = FwhInstance->VolumeHeader.Attributes;
296
297 return EFI_SUCCESS;
298 }
299
300 EFI_STATUS
301 FvbGetLbaAddress (
302 IN UINTN Instance,
303 IN EFI_LBA Lba,
304 OUT UINTN *LbaAddress,
305 OUT UINTN *LbaLength,
306 OUT UINTN *NumOfBlocks,
307 IN ESAL_FWB_GLOBAL *Global,
308 IN BOOLEAN Virtual
309 )
310 /*++
311
312 Routine Description:
313 Retrieves the starting address of an LBA in an FV
314
315 Arguments:
316 Instance - The FV instance which the Lba belongs to
317 Lba - The logical block address
318 LbaAddress - On output, contains the physical starting address
319 of the Lba
320 LbaLength - On output, contains the length of the block
321 NumOfBlocks - A pointer to a caller allocated UINTN in which the
322 number of consecutive blocks starting with Lba is
323 returned. All blocks in this range have a size of
324 BlockSize
325 Global - Pointer to ESAL_FWB_GLOBAL that contains all
326 instance data
327 Virtual - Whether CPU is in virtual or physical mode
328
329 Returns:
330 EFI_SUCCESS - Successfully returns
331 EFI_INVALID_PARAMETER - Instance not found
332
333 --*/
334 {
335 UINT32 NumBlocks;
336 UINT32 BlockLength;
337 UINTN Offset;
338 EFI_LBA StartLba;
339 EFI_LBA NextLba;
340 EFI_FW_VOL_INSTANCE *FwhInstance;
341 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
342 EFI_STATUS Status;
343
344 //
345 // Find the right instance of the FVB private data
346 //
347 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
348 ASSERT_EFI_ERROR (Status);
349
350 StartLba = 0;
351 Offset = 0;
352 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
353
354 //
355 // Parse the blockmap of the FV to find which map entry the Lba belongs to
356 //
357 while (TRUE) {
358 NumBlocks = BlockMap->NumBlocks;
359 BlockLength = BlockMap->Length;
360
361 if (NumBlocks == 0 || BlockLength == 0) {
362 return EFI_INVALID_PARAMETER;
363 }
364
365 NextLba = StartLba + NumBlocks;
366
367 //
368 // The map entry found
369 //
370 if (Lba >= StartLba && Lba < NextLba) {
371 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
372 if (LbaAddress != NULL) {
373 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
374 }
375
376 if (LbaLength != NULL) {
377 *LbaLength = BlockLength;
378 }
379
380 if (NumOfBlocks != NULL) {
381 *NumOfBlocks = (UINTN) (NextLba - Lba);
382 }
383
384 return EFI_SUCCESS;
385 }
386
387 StartLba = NextLba;
388 Offset = Offset + NumBlocks * BlockLength;
389 BlockMap++;
390 }
391 }
392
393 EFI_STATUS
394 FvbReadBlock (
395 IN UINTN Instance,
396 IN EFI_LBA Lba,
397 IN UINTN BlockOffset,
398 IN OUT UINTN *NumBytes,
399 IN UINT8 *Buffer,
400 IN ESAL_FWB_GLOBAL *Global,
401 IN BOOLEAN Virtual
402 )
403 /*++
404
405 Routine Description:
406 Reads specified number of bytes into a buffer from the specified block
407
408 Arguments:
409 Instance - The FV instance to be read from
410 Lba - The logical block address to be read from
411 BlockOffset - Offset into the block at which to begin reading
412 NumBytes - Pointer that on input contains the total size of
413 the buffer. On output, it contains the total number
414 of bytes read
415 Buffer - Pointer to a caller allocated buffer that will be
416 used to hold the data read
417 Global - Pointer to ESAL_FWB_GLOBAL that contains all
418 instance data
419 Virtual - Whether CPU is in virtual or physical mode
420
421 Returns:
422 EFI_SUCCESS - The firmware volume was read successfully and
423 contents are in Buffer
424 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
425 NumBytes contains the total number of bytes returned
426 in Buffer
427 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
428 EFI_DEVICE_ERROR - The block device is not functioning correctly and
429 could not be read
430 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
431
432 --*/
433 {
434 EFI_FVB_ATTRIBUTES_2 Attributes;
435 UINTN LbaAddress;
436 UINTN LbaLength;
437 EFI_STATUS Status;
438
439 //
440 // Check for invalid conditions
441 //
442 if ((NumBytes == NULL) || (Buffer == NULL)) {
443 return EFI_INVALID_PARAMETER;
444 }
445
446 if (*NumBytes == 0) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
451 if (EFI_ERROR (Status)) {
452 return Status;
453 }
454 //
455 // Check if the FV is read enabled
456 //
457 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
458
459 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
460 return EFI_ACCESS_DENIED;
461 }
462 //
463 // Perform boundary checks and adjust NumBytes
464 //
465 if (BlockOffset > LbaLength) {
466 return EFI_INVALID_PARAMETER;
467 }
468
469 if (LbaLength < (*NumBytes + BlockOffset)) {
470 *NumBytes = (UINT32) (LbaLength - BlockOffset);
471 Status = EFI_BAD_BUFFER_SIZE;
472 }
473
474 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));
475
476 return Status;
477 }
478
479 EFI_STATUS
480 FvbWriteBlock (
481 IN UINTN Instance,
482 IN EFI_LBA Lba,
483 IN UINTN BlockOffset,
484 IN OUT UINTN *NumBytes,
485 IN UINT8 *Buffer,
486 IN ESAL_FWB_GLOBAL *Global,
487 IN BOOLEAN Virtual
488 )
489 /*++
490
491 Routine Description:
492 Writes specified number of bytes from the input buffer to the block
493
494 Arguments:
495 Instance - The FV instance to be written to
496 Lba - The starting logical block index to write to
497 BlockOffset - Offset into the block at which to begin writing
498 NumBytes - Pointer that on input contains the total size of
499 the buffer. On output, it contains the total number
500 of bytes actually written
501 Buffer - Pointer to a caller allocated buffer that contains
502 the source for the write
503 Global - Pointer to ESAL_FWB_GLOBAL that contains all
504 instance data
505 Virtual - Whether CPU is in virtual or physical mode
506
507 Returns:
508 EFI_SUCCESS - The firmware volume was written successfully
509 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
510 NumBytes contains the total number of bytes
511 actually written
512 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
513 EFI_DEVICE_ERROR - The block device is not functioning correctly and
514 could not be written
515 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
516
517 --*/
518 {
519 EFI_FVB_ATTRIBUTES_2 Attributes;
520 UINTN LbaAddress;
521 UINTN LbaLength;
522 EFI_STATUS Status;
523
524 //
525 // Check for invalid conditions
526 //
527 if ((NumBytes == NULL) || (Buffer == NULL)) {
528 return EFI_INVALID_PARAMETER;
529 }
530
531 if (*NumBytes == 0) {
532 return EFI_INVALID_PARAMETER;
533 }
534
535 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
536 if (EFI_ERROR (Status)) {
537 return Status;
538 }
539 //
540 // Check if the FV is write enabled
541 //
542 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
543
544 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
545 return EFI_ACCESS_DENIED;
546 }
547 //
548 // Perform boundary checks and adjust NumBytes
549 //
550 if (BlockOffset > LbaLength) {
551 return EFI_INVALID_PARAMETER;
552 }
553
554 if (LbaLength < (*NumBytes + BlockOffset)) {
555 *NumBytes = (UINT32) (LbaLength - BlockOffset);
556 Status = EFI_BAD_BUFFER_SIZE;
557 }
558 //
559 // Write data
560 //
561 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));
562
563 return Status;
564 }
565
566 EFI_STATUS
567 FvbEraseBlock (
568 IN UINTN Instance,
569 IN EFI_LBA Lba,
570 IN ESAL_FWB_GLOBAL *Global,
571 IN BOOLEAN Virtual
572 )
573 /*++
574
575 Routine Description:
576 Erases and initializes a firmware volume block
577
578 Arguments:
579 Instance - The FV instance to be erased
580 Lba - The logical block index to be erased
581 Global - Pointer to ESAL_FWB_GLOBAL that contains all
582 instance data
583 Virtual - Whether CPU is in virtual or physical mode
584
585 Returns:
586 EFI_SUCCESS - The erase request was successfully completed
587 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
588 EFI_DEVICE_ERROR - The block device is not functioning correctly and
589 could not be written. Firmware device may have been
590 partially erased
591 EFI_INVALID_PARAMETER - Instance not found
592
593 --*/
594 {
595
596 EFI_FVB_ATTRIBUTES_2 Attributes;
597 UINTN LbaAddress;
598 UINTN LbaLength;
599 EFI_STATUS Status;
600 UINT8 Data;
601
602 //
603 // Check if the FV is write enabled
604 //
605 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
606
607 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
608 return EFI_ACCESS_DENIED;
609 }
610 //
611 // Get the starting address of the block for erase.
612 //
613 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
614
615 if (EFI_ERROR (Status)) {
616 return Status;
617 }
618
619 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
620 Data = 0xFF;
621 } else {
622 Data = 0x0;
623 }
624
625 SetMem ((UINT8 *) LbaAddress, LbaLength, Data);
626
627 return EFI_SUCCESS;
628 }
629
630 EFI_STATUS
631 FvbSetVolumeAttributes (
632 IN UINTN Instance,
633 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
634 IN ESAL_FWB_GLOBAL *Global,
635 IN BOOLEAN Virtual
636 )
637 /*++
638
639 Routine Description:
640 Modifies the current settings of the firmware volume according to the
641 input parameter, and returns the new setting of the volume
642
643 Arguments:
644 Instance - The FV instance whose attributes is going to be
645 modified
646 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
647 containing the desired firmware volume settings.
648 On successful return, it contains the new settings
649 of the firmware volume
650 Global - Pointer to ESAL_FWB_GLOBAL that contains all
651 instance data
652 Virtual - Whether CPU is in virtual or physical mode
653
654 Returns:
655 EFI_SUCCESS - Successfully returns
656 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
657 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
658 in conflict with the capabilities as declared in the
659 firmware volume header
660
661 --*/
662 {
663 EFI_FW_VOL_INSTANCE *FwhInstance;
664 EFI_FVB_ATTRIBUTES_2 OldAttributes;
665 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
666 UINT32 Capabilities;
667 UINT32 OldStatus;
668 UINT32 NewStatus;
669 EFI_STATUS Status;
670 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
671
672 //
673 // Find the right instance of the FVB private data
674 //
675 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
676 ASSERT_EFI_ERROR (Status);
677
678 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
679 OldAttributes = *AttribPtr;
680 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
681 EFI_FVB2_READ_ENABLED_CAP | \
682 EFI_FVB2_WRITE_DISABLED_CAP | \
683 EFI_FVB2_WRITE_ENABLED_CAP | \
684 EFI_FVB2_LOCK_CAP \
685 );
686 OldStatus = OldAttributes & EFI_FVB2_STATUS;
687 NewStatus = *Attributes & EFI_FVB2_STATUS;
688
689 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
690 EFI_FVB2_READ_ENABLED_CAP | \
691 EFI_FVB2_WRITE_DISABLED_CAP | \
692 EFI_FVB2_WRITE_ENABLED_CAP | \
693 EFI_FVB2_LOCK_CAP | \
694 EFI_FVB2_STICKY_WRITE | \
695 EFI_FVB2_MEMORY_MAPPED | \
696 EFI_FVB2_ERASE_POLARITY | \
697 EFI_FVB2_READ_LOCK_CAP | \
698 EFI_FVB2_WRITE_LOCK_CAP | \
699 EFI_FVB2_ALIGNMENT;
700
701 //
702 // Some attributes of FV is read only can *not* be set
703 //
704 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
705 return EFI_INVALID_PARAMETER;
706 }
707 //
708 // If firmware volume is locked, no status bit can be updated
709 //
710 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
711 if (OldStatus ^ NewStatus) {
712 return EFI_ACCESS_DENIED;
713 }
714 }
715 //
716 // Test read disable
717 //
718 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
719 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
720 return EFI_INVALID_PARAMETER;
721 }
722 }
723 //
724 // Test read enable
725 //
726 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
727 if (NewStatus & EFI_FVB2_READ_STATUS) {
728 return EFI_INVALID_PARAMETER;
729 }
730 }
731 //
732 // Test write disable
733 //
734 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
735 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
736 return EFI_INVALID_PARAMETER;
737 }
738 }
739 //
740 // Test write enable
741 //
742 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
743 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
744 return EFI_INVALID_PARAMETER;
745 }
746 }
747 //
748 // Test lock
749 //
750 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
751 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
752 return EFI_INVALID_PARAMETER;
753 }
754 }
755
756 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
757 *AttribPtr = (*AttribPtr) | NewStatus;
758 *Attributes = *AttribPtr;
759
760 return EFI_SUCCESS;
761 }
762 //
763 // FVB protocol APIs
764 //
765 EFI_STATUS
766 EFIAPI
767 FvbProtocolGetPhysicalAddress (
768 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
769 OUT EFI_PHYSICAL_ADDRESS *Address
770 )
771 /*++
772
773 Routine Description:
774
775 Retrieves the physical address of the device.
776
777 Arguments:
778
779 This - Calling context
780 Address - Output buffer containing the address.
781
782 Returns:
783
784 Returns:
785 EFI_SUCCESS - Successfully returns
786
787 --*/
788 {
789 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
790
791 FvbDevice = FVB_DEVICE_FROM_THIS (This);
792
793 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
794 }
795
796 EFI_STATUS
797 EFIAPI
798 FvbProtocolGetBlockSize (
799 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
800 IN CONST EFI_LBA Lba,
801 OUT UINTN *BlockSize,
802 OUT UINTN *NumOfBlocks
803 )
804 /*++
805
806 Routine Description:
807 Retrieve the size of a logical block
808
809 Arguments:
810 This - Calling context
811 Lba - Indicates which block to return the size for.
812 BlockSize - A pointer to a caller allocated UINTN in which
813 the size of the block is returned
814 NumOfBlocks - a pointer to a caller allocated UINTN in which the
815 number of consecutive blocks starting with Lba is
816 returned. All blocks in this range have a size of
817 BlockSize
818
819 Returns:
820 EFI_SUCCESS - The firmware volume was read successfully and
821 contents are in Buffer
822
823 --*/
824 {
825 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
826
827 FvbDevice = FVB_DEVICE_FROM_THIS (This);
828
829 return FvbGetLbaAddress (
830 FvbDevice->Instance,
831 Lba,
832 NULL,
833 BlockSize,
834 NumOfBlocks,
835 mFvbModuleGlobal,
836 EfiGoneVirtual ()
837 );
838 }
839
840 EFI_STATUS
841 EFIAPI
842 FvbProtocolGetAttributes (
843 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
844 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
845 )
846 /*++
847
848 Routine Description:
849 Retrieves Volume attributes. No polarity translations are done.
850
851 Arguments:
852 This - Calling context
853 Attributes - output buffer which contains attributes
854
855 Returns:
856 EFI_SUCCESS - Successfully returns
857
858 --*/
859 {
860 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
861
862 FvbDevice = FVB_DEVICE_FROM_THIS (This);
863
864 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
865 }
866
867 EFI_STATUS
868 EFIAPI
869 FvbProtocolSetAttributes (
870 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
871 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
872 )
873 /*++
874
875 Routine Description:
876 Sets Volume attributes. No polarity translations are done.
877
878 Arguments:
879 This - Calling context
880 Attributes - output buffer which contains attributes
881
882 Returns:
883 EFI_SUCCESS - Successfully returns
884
885 --*/
886 {
887 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
888
889 FvbDevice = FVB_DEVICE_FROM_THIS (This);
890
891 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
892 }
893
894 EFI_STATUS
895 EFIAPI
896 FvbProtocolEraseBlocks (
897 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
898 ...
899 )
900 /*++
901
902 Routine Description:
903
904 The EraseBlock() function erases one or more blocks as denoted by the
905 variable argument list. The entire parameter list of blocks must be verified
906 prior to erasing any blocks. If a block is requested that does not exist
907 within the associated firmware volume (it has a larger index than the last
908 block of the firmware volume), the EraseBlock() function must return
909 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
910
911 Arguments:
912 This - Calling context
913 ... - Starting LBA followed by Number of Lba to erase.
914 a -1 to terminate the list.
915
916 Returns:
917 EFI_SUCCESS - The erase request was successfully completed
918 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
919 EFI_DEVICE_ERROR - The block device is not functioning correctly and
920 could not be written. Firmware device may have been
921 partially erased
922
923 --*/
924 {
925 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
926 EFI_FW_VOL_INSTANCE *FwhInstance;
927 UINTN NumOfBlocks;
928 VA_LIST args;
929 EFI_LBA StartingLba;
930 UINTN NumOfLba;
931 EFI_STATUS Status;
932
933 FvbDevice = FVB_DEVICE_FROM_THIS (This);
934
935 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
936 ASSERT_EFI_ERROR (Status);
937
938 NumOfBlocks = FwhInstance->NumOfBlocks;
939
940 VA_START (args, This);
941
942 do {
943 StartingLba = VA_ARG (args, EFI_LBA);
944 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
945 break;
946 }
947
948 NumOfLba = VA_ARG (args, UINT32);
949
950 //
951 // Check input parameters
952 //
953 if (NumOfLba == 0) {
954 VA_END (args);
955 return EFI_INVALID_PARAMETER;
956 }
957
958 if ((StartingLba + NumOfLba) > NumOfBlocks) {
959 return EFI_INVALID_PARAMETER;
960 }
961 } while (1);
962
963 VA_END (args);
964
965 VA_START (args, This);
966 do {
967 StartingLba = VA_ARG (args, EFI_LBA);
968 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
969 break;
970 }
971
972 NumOfLba = VA_ARG (args, UINT32);
973
974 while (NumOfLba > 0) {
975 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
976 if (EFI_ERROR (Status)) {
977 VA_END (args);
978 return Status;
979 }
980
981 StartingLba++;
982 NumOfLba--;
983 }
984
985 } while (1);
986
987 VA_END (args);
988
989 return EFI_SUCCESS;
990 }
991
992 EFI_STATUS
993 EFIAPI
994 FvbProtocolWrite (
995 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
996 IN EFI_LBA Lba,
997 IN UINTN Offset,
998 IN OUT UINTN *NumBytes,
999 IN UINT8 *Buffer
1000 )
1001 /*++
1002
1003 Routine Description:
1004
1005 Writes data beginning at Lba:Offset from FV. The write terminates either
1006 when *NumBytes of data have been written, or when a block boundary is
1007 reached. *NumBytes is updated to reflect the actual number of bytes
1008 written. The write opertion does not include erase. This routine will
1009 attempt to write only the specified bytes. If the writes do not stick,
1010 it will return an error.
1011
1012 Arguments:
1013 This - Calling context
1014 Lba - Block in which to begin write
1015 Offset - Offset in the block at which to begin write
1016 NumBytes - On input, indicates the requested write size. On
1017 output, indicates the actual number of bytes written
1018 Buffer - Buffer containing source data for the write.
1019
1020 Returns:
1021 EFI_SUCCESS - The firmware volume was written successfully
1022 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1023 NumBytes contains the total number of bytes
1024 actually written
1025 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1026 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1027 could not be written
1028 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1029
1030 --*/
1031 {
1032
1033 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1034
1035 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1036
1037 return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1038 }
1039
1040 EFI_STATUS
1041 EFIAPI
1042 FvbProtocolRead (
1043 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1044 IN CONST EFI_LBA Lba,
1045 IN CONST UINTN Offset,
1046 IN OUT UINTN *NumBytes,
1047 IN UINT8 *Buffer
1048 )
1049 /*++
1050
1051 Routine Description:
1052
1053 Reads data beginning at Lba:Offset from FV. The Read terminates either
1054 when *NumBytes of data have been read, or when a block boundary is
1055 reached. *NumBytes is updated to reflect the actual number of bytes
1056 written. The write opertion does not include erase. This routine will
1057 attempt to write only the specified bytes. If the writes do not stick,
1058 it will return an error.
1059
1060 Arguments:
1061 This - Calling context
1062 Lba - Block in which to begin Read
1063 Offset - Offset in the block at which to begin Read
1064 NumBytes - On input, indicates the requested write size. On
1065 output, indicates the actual number of bytes Read
1066 Buffer - Buffer containing source data for the Read.
1067
1068 Returns:
1069 EFI_SUCCESS - The firmware volume was read successfully and
1070 contents are in Buffer
1071 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1072 NumBytes contains the total number of bytes returned
1073 in Buffer
1074 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1075 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1076 could not be read
1077 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1078
1079 --*/
1080 {
1081
1082 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1083
1084 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1085
1086 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1087 }
1088
1089 EFI_STATUS
1090 ValidateFvHeader (
1091 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
1092 )
1093 /*++
1094
1095 Routine Description:
1096 Check the integrity of firmware volume header
1097
1098 Arguments:
1099 FwVolHeader - A pointer to a firmware volume header
1100
1101 Returns:
1102 EFI_SUCCESS - The firmware volume is consistent
1103 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1104
1105 --*/
1106 {
1107 //
1108 // Verify the header revision, header signature, length
1109 // Length of FvBlock cannot be 2**64-1
1110 // HeaderLength cannot be an odd number
1111 //
1112 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1113 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1114 (FwVolHeader->FvLength == ((UINTN) -1)) ||
1115 ((FwVolHeader->HeaderLength & 0x01) != 0)
1116 ) {
1117 return EFI_NOT_FOUND;
1118 }
1119
1120 //
1121 // Verify the header checksum
1122 //
1123 if (CalculateCheckSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength) != 0) {
1124 return EFI_NOT_FOUND;
1125 }
1126
1127 return EFI_SUCCESS;
1128 }
1129
1130 EFI_STATUS
1131 EFIAPI
1132 FvbInitialize (
1133 IN EFI_HANDLE ImageHandle,
1134 IN EFI_SYSTEM_TABLE *SystemTable
1135 )
1136 /*++
1137
1138 Routine Description:
1139 This function does common initialization for FVB services
1140
1141 Arguments:
1142
1143 Returns:
1144
1145 --*/
1146 {
1147 EFI_STATUS Status;
1148 EFI_FW_VOL_INSTANCE *FwhInstance;
1149 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1150 EFI_DXE_SERVICES *DxeServices;
1151 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1152 UINT32 BufferSize;
1153 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1154 EFI_HANDLE FwbHandle;
1155 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1156 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1157 UINT32 MaxLbaSize;
1158 EFI_PHYSICAL_ADDRESS BaseAddress;
1159 UINT64 Length;
1160 UINTN NumOfBlocks;
1161 EFI_PEI_HOB_POINTERS FvHob;
1162
1163 //
1164 // Get the DXE services table
1165 //
1166 DxeServices = gDS;
1167
1168 //
1169 // Allocate runtime services data for global variable, which contains
1170 // the private data of all firmware volume block instances
1171 //
1172 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
1173 ASSERT (mFvbModuleGlobal != NULL);
1174
1175 //
1176 // Calculate the total size for all firmware volume block instances
1177 //
1178 BufferSize = 0;
1179
1180 FvHob.Raw = GetHobList ();
1181 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1182 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1183 Length = FvHob.FirmwareVolume->Length;
1184 //
1185 // Check if it is a "real" flash
1186 //
1187 Status = DxeServices->GetMemorySpaceDescriptor (
1188 BaseAddress,
1189 &Descriptor
1190 );
1191 if (EFI_ERROR (Status)) {
1192 break;
1193 }
1194
1195 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1196 FvHob.Raw = GET_NEXT_HOB (FvHob);
1197 continue;
1198 }
1199
1200 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1201 Status = ValidateFvHeader (FwVolHeader);
1202 if (EFI_ERROR (Status)) {
1203 //
1204 // Get FvbInfo
1205 //
1206 Status = GetFvbInfo (Length, &FwVolHeader);
1207 if (EFI_ERROR (Status)) {
1208 FvHob.Raw = GET_NEXT_HOB (FvHob);
1209 continue;
1210 }
1211 }
1212
1213 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1214 FvHob.Raw = GET_NEXT_HOB (FvHob);
1215 }
1216
1217 //
1218 // Only need to allocate once. There is only one copy of physical memory for
1219 // the private data of each FV instance. But in virtual mode or in physical
1220 // mode, the address of the the physical memory may be different.
1221 //
1222 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);
1223 ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);
1224
1225 //
1226 // Make a virtual copy of the FvInstance pointer.
1227 //
1228 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1229 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1230
1231 mFvbModuleGlobal->NumFv = 0;
1232 MaxLbaSize = 0;
1233
1234 FvHob.Raw = GetHobList ();
1235 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1236 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1237 Length = FvHob.FirmwareVolume->Length;
1238 //
1239 // Check if it is a "real" flash
1240 //
1241 Status = DxeServices->GetMemorySpaceDescriptor (
1242 BaseAddress,
1243 &Descriptor
1244 );
1245 if (EFI_ERROR (Status)) {
1246 break;
1247 }
1248
1249 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1250 FvHob.Raw = GET_NEXT_HOB (FvHob);
1251 continue;
1252 }
1253
1254 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1255 Status = ValidateFvHeader (FwVolHeader);
1256 if (EFI_ERROR (Status)) {
1257 //
1258 // Get FvbInfo to provide in FwhInstance.
1259 //
1260 Status = GetFvbInfo (Length, &FwVolHeader);
1261 if (EFI_ERROR (Status)) {
1262 FvHob.Raw = GET_NEXT_HOB (FvHob);
1263 continue;
1264 }
1265 //
1266 // Write healthy FV header back.
1267 //
1268 CopyMem (
1269 (VOID *) (UINTN) BaseAddress,
1270 (VOID *) FwVolHeader,
1271 FwVolHeader->HeaderLength
1272 );
1273 }
1274
1275 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1276 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1277
1278 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1279 FwVolHeader = &(FwhInstance->VolumeHeader);
1280 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1281
1282 NumOfBlocks = 0;
1283
1284 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1285 //
1286 // Get the maximum size of a block.
1287 //
1288 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1289 MaxLbaSize = PtrBlockMapEntry->Length;
1290 }
1291
1292 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1293 }
1294 //
1295 // The total number of blocks in the FV.
1296 //
1297 FwhInstance->NumOfBlocks = NumOfBlocks;
1298
1299 //
1300 // Add a FVB Protocol Instance
1301 //
1302 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1303 ASSERT (FvbDevice != NULL);
1304
1305 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1306
1307 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1308 mFvbModuleGlobal->NumFv++;
1309
1310
1311 //
1312 // Set up the devicepath
1313 //
1314 if (FwVolHeader->ExtHeaderOffset == 0) {
1315 //
1316 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1317 //
1318 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
1319 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
1320 ((FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath)->MemMapDevPath.EndingAddress = BaseAddress + FwVolHeader->FvLength - 1;
1321 } else {
1322 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
1323 CopyGuid (
1324 &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
1325 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
1326 );
1327 }
1328 //
1329 // Find a handle with a matching device path that has supports FW Block protocol
1330 //
1331 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &FvbDevice->DevicePath, &FwbHandle);
1332 if (EFI_ERROR (Status)) {
1333 //
1334 // LocateDevicePath fails so install a new interface and device path
1335 //
1336 FwbHandle = NULL;
1337 Status = gBS->InstallMultipleProtocolInterfaces (
1338 &FwbHandle,
1339 &gEfiFirmwareVolumeBlockProtocolGuid,
1340 &FvbDevice->FwVolBlockInstance,
1341 &gEfiDevicePathProtocolGuid,
1342 &FvbDevice->DevicePath,
1343 NULL
1344 );
1345 ASSERT_EFI_ERROR (Status);
1346 } else if (IsDevicePathEnd (FvbDevice->DevicePath)) {
1347 //
1348 // Device allready exists, so reinstall the FVB protocol
1349 //
1350 Status = gBS->HandleProtocol (
1351 FwbHandle,
1352 &gEfiFirmwareVolumeBlockProtocolGuid,
1353 (VOID**)&OldFwbInterface
1354 );
1355 ASSERT_EFI_ERROR (Status);
1356
1357 Status = gBS->ReinstallProtocolInterface (
1358 FwbHandle,
1359 &gEfiFirmwareVolumeBlockProtocolGuid,
1360 OldFwbInterface,
1361 &FvbDevice->FwVolBlockInstance
1362 );
1363 ASSERT_EFI_ERROR (Status);
1364
1365 } else {
1366 //
1367 // There was a FVB protocol on an End Device Path node
1368 //
1369 ASSERT (FALSE);
1370 }
1371
1372 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1373 (
1374 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1375 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1376 );
1377
1378 FvHob.Raw = GET_NEXT_HOB (FvHob);
1379 }
1380
1381 return EFI_SUCCESS;
1382 }