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