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