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