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