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