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