I fixed following bugs in EDKII.
[mirror_edk2.git] / EdkNt32Pkg / RuntimeDxe / FvbServices / 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 = Checksum + (*Ptr);
1200 HeaderLength--;
1201 Ptr++;
1202 }
1203
1204 if (Checksum != 0) {
1205 return EFI_NOT_FOUND;
1206 }
1207
1208 return EFI_SUCCESS;
1209 }
1210
1211 EFI_STATUS
1212 EFIAPI
1213 FvbInitialize (
1214 IN EFI_HANDLE ImageHandle,
1215 IN EFI_SYSTEM_TABLE *SystemTable
1216 )
1217 /*++
1218
1219 Routine Description:
1220 This function does common initialization for FVB services
1221
1222 Arguments:
1223
1224 Returns:
1225
1226 --*/
1227 {
1228 EFI_STATUS Status;
1229 EFI_FW_VOL_INSTANCE *FwhInstance;
1230 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1231 EFI_DXE_SERVICES *DxeServices;
1232 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1233 UINT32 BufferSize;
1234 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1235 EFI_HANDLE FwbHandle;
1236 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1237 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1238 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;
1239 FV_DEVICE_PATH TempFvbDevicePathData;
1240 UINT32 MaxLbaSize;
1241 EFI_PHYSICAL_ADDRESS BaseAddress;
1242 UINT64 Length;
1243 UINTN NumOfBlocks;
1244 EFI_PEI_HOB_POINTERS FvHob;
1245
1246 //
1247 // Get the DXE services table
1248 //
1249 DxeServices = gDS;
1250
1251 //
1252 // Allocate runtime services data for global variable, which contains
1253 // the private data of all firmware volume block instances
1254 //
1255 Status = gBS->AllocatePool (
1256 EfiRuntimeServicesData,
1257 sizeof (ESAL_FWB_GLOBAL),
1258 &mFvbModuleGlobal
1259 );
1260 ASSERT_EFI_ERROR (Status);
1261
1262 //
1263 // Calculate the total size for all firmware volume block instances
1264 //
1265 BufferSize = 0;
1266
1267 FvHob.Raw = GetHobList ();
1268 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1269 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1270 Length = FvHob.FirmwareVolume->Length;
1271 //
1272 // Check if it is a "real" flash
1273 //
1274 Status = DxeServices->GetMemorySpaceDescriptor (
1275 BaseAddress,
1276 &Descriptor
1277 );
1278 if (EFI_ERROR (Status)) {
1279 break;
1280 }
1281
1282 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1283 FvHob.Raw = GET_NEXT_HOB (FvHob);
1284 continue;
1285 }
1286
1287 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1288 Status = ValidateFvHeader (FwVolHeader);
1289 if (EFI_ERROR (Status)) {
1290 //
1291 // Get FvbInfo
1292 //
1293 Status = GetFvbInfo (Length, &FwVolHeader);
1294 if (EFI_ERROR (Status)) {
1295 FvHob.Raw = GET_NEXT_HOB (FvHob);
1296 continue;
1297 }
1298 }
1299
1300 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1301 FvHob.Raw = GET_NEXT_HOB (FvHob);
1302 }
1303
1304 //
1305 // Only need to allocate once. There is only one copy of physical memory for
1306 // the private data of each FV instance. But in virtual mode or in physical
1307 // mode, the address of the the physical memory may be different.
1308 //
1309 Status = gBS->AllocatePool (
1310 EfiRuntimeServicesData,
1311 BufferSize,
1312 &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
1313 );
1314 ASSERT_EFI_ERROR (Status);
1315
1316 //
1317 // Make a virtual copy of the FvInstance pointer.
1318 //
1319 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1320 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1321
1322 mFvbModuleGlobal->NumFv = 0;
1323 MaxLbaSize = 0;
1324
1325 FvHob.Raw = GetHobList ();
1326 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1327 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1328 Length = FvHob.FirmwareVolume->Length;
1329 //
1330 // Check if it is a "real" flash
1331 //
1332 Status = DxeServices->GetMemorySpaceDescriptor (
1333 BaseAddress,
1334 &Descriptor
1335 );
1336 if (EFI_ERROR (Status)) {
1337 break;
1338 }
1339
1340 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1341 FvHob.Raw = GET_NEXT_HOB (FvHob);
1342 continue;
1343 }
1344
1345 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1346 Status = ValidateFvHeader (FwVolHeader);
1347 if (EFI_ERROR (Status)) {
1348 //
1349 // Get FvbInfo to provide in FwhInstance.
1350 //
1351 Status = GetFvbInfo (Length, &FwVolHeader);
1352 if (EFI_ERROR (Status)) {
1353 FvHob.Raw = GET_NEXT_HOB (FvHob);
1354 continue;
1355 }
1356 //
1357 // Write healthy FV header back.
1358 //
1359 CopyMem (
1360 (VOID *) (UINTN) BaseAddress,
1361 (VOID *) FwVolHeader,
1362 FwVolHeader->HeaderLength
1363 );
1364 }
1365
1366 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1367 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1368
1369 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1370 FwVolHeader = &(FwhInstance->VolumeHeader);
1371 EfiInitializeLock (&(FwhInstance->FvbDevLock), EFI_TPL_HIGH_LEVEL);
1372
1373 NumOfBlocks = 0;
1374
1375 for (PtrBlockMapEntry = FwVolHeader->FvBlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1376 //
1377 // Get the maximum size of a block. The size will be used to allocate
1378 // buffer for Scratch space, the intermediate buffer for FVB extension
1379 // protocol
1380 //
1381 if (MaxLbaSize < PtrBlockMapEntry->BlockLength) {
1382 MaxLbaSize = PtrBlockMapEntry->BlockLength;
1383 }
1384
1385 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1386 }
1387 //
1388 // The total number of blocks in the FV.
1389 //
1390 FwhInstance->NumOfBlocks = NumOfBlocks;
1391
1392 //
1393 // Add a FVB Protocol Instance
1394 //
1395 Status = gBS->AllocatePool (
1396 EfiRuntimeServicesData,
1397 sizeof (EFI_FW_VOL_BLOCK_DEVICE),
1398 &FvbDevice
1399 );
1400 ASSERT_EFI_ERROR (Status);
1401
1402 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1403
1404 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1405 mFvbModuleGlobal->NumFv++;
1406
1407 //
1408 // Set up the devicepath
1409 //
1410 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1411 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);
1412
1413 //
1414 // Find a handle with a matching device path that has supports FW Block protocol
1415 //
1416 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1417 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1418 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1419 if (EFI_ERROR (Status)) {
1420 //
1421 // LocateDevicePath fails so install a new interface and device path
1422 //
1423 FwbHandle = NULL;
1424 Status = gBS->InstallMultipleProtocolInterfaces (
1425 &FwbHandle,
1426 &gEfiFirmwareVolumeBlockProtocolGuid,
1427 &FvbDevice->FwVolBlockInstance,
1428 &gEfiDevicePathProtocolGuid,
1429 &FvbDevice->DevicePath,
1430 NULL
1431 );
1432 ASSERT_EFI_ERROR (Status);
1433 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {
1434 //
1435 // Device allready exists, so reinstall the FVB protocol
1436 //
1437 Status = gBS->HandleProtocol (
1438 FwbHandle,
1439 &gEfiFirmwareVolumeBlockProtocolGuid,
1440 &OldFwbInterface
1441 );
1442 ASSERT_EFI_ERROR (Status);
1443
1444 Status = gBS->ReinstallProtocolInterface (
1445 FwbHandle,
1446 &gEfiFirmwareVolumeBlockProtocolGuid,
1447 OldFwbInterface,
1448 &FvbDevice->FwVolBlockInstance
1449 );
1450 ASSERT_EFI_ERROR (Status);
1451
1452 } else {
1453 //
1454 // There was a FVB protocol on an End Device Path node
1455 //
1456 ASSERT (FALSE);
1457 }
1458 //
1459 // Install FVB Extension Protocol on the same handle
1460 //
1461 Status = gBS->InstallMultipleProtocolInterfaces (
1462 &FwbHandle,
1463 &gEfiFvbExtensionProtocolGuid,
1464 &FvbDevice->FvbExtension,
1465 &gEfiAlternateFvBlockGuid,
1466 NULL,
1467 NULL
1468 );
1469
1470 ASSERT_EFI_ERROR (Status);
1471
1472 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1473 (
1474 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1475 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1476 );
1477
1478 FvHob.Raw = GET_NEXT_HOB (FvHob);
1479 }
1480
1481 //
1482 // Allocate for scratch space, an intermediate buffer for FVB extention
1483 //
1484 Status = gBS->AllocatePool (
1485 EfiRuntimeServicesData,
1486 MaxLbaSize,
1487 &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]
1488 );
1489 ASSERT_EFI_ERROR (Status);
1490
1491 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
1492
1493 return EFI_SUCCESS;
1494 }