]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/FvbServicesRuntimeDxe/FWBlockService.c
Fix some bugs in DSC/INF file Nt32 platform
[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 EFI_FVB_ATTRIBUTES UnchangedAttributes;
744
745 //
746 // Find the right instance of the FVB private data
747 //
748 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
749 ASSERT_EFI_ERROR (Status);
750
751 AttribPtr = (EFI_FVB_ATTRIBUTES *) &(FwhInstance->VolumeHeader.Attributes);
752 OldAttributes = *AttribPtr;
753 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
754 EFI_FVB2_READ_ENABLED_CAP | \
755 EFI_FVB2_WRITE_DISABLED_CAP | \
756 EFI_FVB2_WRITE_ENABLED_CAP | \
757 EFI_FVB2_LOCK_CAP \
758 );
759 OldStatus = OldAttributes & EFI_FVB2_STATUS;
760 NewStatus = *Attributes & EFI_FVB2_STATUS;
761
762 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
763 EFI_FVB2_READ_ENABLED_CAP | \
764 EFI_FVB2_WRITE_DISABLED_CAP | \
765 EFI_FVB2_WRITE_ENABLED_CAP | \
766 EFI_FVB2_LOCK_CAP | \
767 EFI_FVB2_STICKY_WRITE | \
768 EFI_FVB2_MEMORY_MAPPED | \
769 EFI_FVB2_ERASE_POLARITY | \
770 EFI_FVB2_READ_LOCK_CAP | \
771 EFI_FVB2_WRITE_LOCK_CAP | \
772 EFI_FVB2_ALIGNMENT;
773
774 //
775 // Some attributes of FV is read only can *not* be set
776 //
777 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
778 return EFI_INVALID_PARAMETER;
779 }
780 //
781 // If firmware volume is locked, no status bit can be updated
782 //
783 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
784 if (OldStatus ^ NewStatus) {
785 return EFI_ACCESS_DENIED;
786 }
787 }
788 //
789 // Test read disable
790 //
791 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
792 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
793 return EFI_INVALID_PARAMETER;
794 }
795 }
796 //
797 // Test read enable
798 //
799 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
800 if (NewStatus & EFI_FVB2_READ_STATUS) {
801 return EFI_INVALID_PARAMETER;
802 }
803 }
804 //
805 // Test write disable
806 //
807 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
808 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
809 return EFI_INVALID_PARAMETER;
810 }
811 }
812 //
813 // Test write enable
814 //
815 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
816 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
817 return EFI_INVALID_PARAMETER;
818 }
819 }
820 //
821 // Test lock
822 //
823 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
824 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
825 return EFI_INVALID_PARAMETER;
826 }
827 }
828
829 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
830 *AttribPtr = (*AttribPtr) | NewStatus;
831 *Attributes = *AttribPtr;
832
833 return EFI_SUCCESS;
834 }
835 //
836 // FVB protocol APIs
837 //
838 EFI_STATUS
839 EFIAPI
840 FvbProtocolGetPhysicalAddress (
841 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
842 OUT EFI_PHYSICAL_ADDRESS *Address
843 )
844 /*++
845
846 Routine Description:
847
848 Retrieves the physical address of the device.
849
850 Arguments:
851
852 This - Calling context
853 Address - Output buffer containing the address.
854
855 Returns:
856
857 Returns:
858 EFI_SUCCESS - Successfully returns
859
860 --*/
861 {
862 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
863
864 FvbDevice = FVB_DEVICE_FROM_THIS (This);
865
866 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
867 }
868
869 EFI_STATUS
870 EFIAPI
871 FvbProtocolGetBlockSize (
872 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
873 IN CONST EFI_LBA Lba,
874 OUT UINTN *BlockSize,
875 OUT UINTN *NumOfBlocks
876 )
877 /*++
878
879 Routine Description:
880 Retrieve the size of a logical block
881
882 Arguments:
883 This - Calling context
884 Lba - Indicates which block to return the size for.
885 BlockSize - A pointer to a caller allocated UINTN in which
886 the size of the block is returned
887 NumOfBlocks - a pointer to a caller allocated UINTN in which the
888 number of consecutive blocks starting with Lba is
889 returned. All blocks in this range have a size of
890 BlockSize
891
892 Returns:
893 EFI_SUCCESS - The firmware volume was read successfully and
894 contents are in Buffer
895
896 --*/
897 {
898 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
899
900 FvbDevice = FVB_DEVICE_FROM_THIS (This);
901
902 return FvbGetLbaAddress (
903 FvbDevice->Instance,
904 Lba,
905 NULL,
906 BlockSize,
907 NumOfBlocks,
908 mFvbModuleGlobal,
909 EfiGoneVirtual ()
910 );
911 }
912
913 EFI_STATUS
914 EFIAPI
915 FvbProtocolGetAttributes (
916 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
917 OUT EFI_FVB_ATTRIBUTES *Attributes
918 )
919 /*++
920
921 Routine Description:
922 Retrieves Volume attributes. No polarity translations are done.
923
924 Arguments:
925 This - Calling context
926 Attributes - output buffer which contains attributes
927
928 Returns:
929 EFI_SUCCESS - Successfully returns
930
931 --*/
932 {
933 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
934
935 FvbDevice = FVB_DEVICE_FROM_THIS (This);
936
937 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
938 }
939
940 EFI_STATUS
941 EFIAPI
942 FvbProtocolSetAttributes (
943 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
944 IN OUT EFI_FVB_ATTRIBUTES *Attributes
945 )
946 /*++
947
948 Routine Description:
949 Sets Volume attributes. No polarity translations are done.
950
951 Arguments:
952 This - Calling context
953 Attributes - output buffer which contains attributes
954
955 Returns:
956 EFI_SUCCESS - Successfully returns
957
958 --*/
959 {
960 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
961
962 FvbDevice = FVB_DEVICE_FROM_THIS (This);
963
964 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
965 }
966
967 EFI_STATUS
968 EFIAPI
969 FvbProtocolEraseBlocks (
970 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
971 ...
972 )
973 /*++
974
975 Routine Description:
976
977 The EraseBlock() function erases one or more blocks as denoted by the
978 variable argument list. The entire parameter list of blocks must be verified
979 prior to erasing any blocks. If a block is requested that does not exist
980 within the associated firmware volume (it has a larger index than the last
981 block of the firmware volume), the EraseBlock() function must return
982 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
983
984 Arguments:
985 This - Calling context
986 ... - Starting LBA followed by Number of Lba to erase.
987 a -1 to terminate the list.
988
989 Returns:
990 EFI_SUCCESS - The erase request was successfully completed
991 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
992 EFI_DEVICE_ERROR - The block device is not functioning correctly and
993 could not be written. Firmware device may have been
994 partially erased
995
996 --*/
997 {
998 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
999 EFI_FW_VOL_INSTANCE *FwhInstance;
1000 UINTN NumOfBlocks;
1001 VA_LIST args;
1002 EFI_LBA StartingLba;
1003 UINTN NumOfLba;
1004 EFI_STATUS Status;
1005
1006 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1007
1008 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
1009 ASSERT_EFI_ERROR (Status);
1010
1011 NumOfBlocks = FwhInstance->NumOfBlocks;
1012
1013 VA_START (args, This);
1014
1015 do {
1016 StartingLba = VA_ARG (args, EFI_LBA);
1017 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1018 break;
1019 }
1020
1021 NumOfLba = VA_ARG (args, UINT32);
1022
1023 //
1024 // Check input parameters
1025 //
1026 if (NumOfLba == 0) {
1027 VA_END (args);
1028 return EFI_INVALID_PARAMETER;
1029 }
1030
1031 if ((StartingLba + NumOfLba) > NumOfBlocks) {
1032 return EFI_INVALID_PARAMETER;
1033 }
1034 } while (1);
1035
1036 VA_END (args);
1037
1038 VA_START (args, This);
1039 do {
1040 StartingLba = VA_ARG (args, EFI_LBA);
1041 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1042 break;
1043 }
1044
1045 NumOfLba = VA_ARG (args, UINT32);
1046
1047 while (NumOfLba > 0) {
1048 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
1049 if (EFI_ERROR (Status)) {
1050 VA_END (args);
1051 return Status;
1052 }
1053
1054 StartingLba++;
1055 NumOfLba--;
1056 }
1057
1058 } while (1);
1059
1060 VA_END (args);
1061
1062 return EFI_SUCCESS;
1063 }
1064
1065 EFI_STATUS
1066 EFIAPI
1067 FvbProtocolWrite (
1068 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1069 IN CONST EFI_LBA Lba,
1070 IN CONST UINTN Offset,
1071 IN OUT UINTN *NumBytes,
1072 IN CONST UINT8 *Buffer
1073 )
1074 /*++
1075
1076 Routine Description:
1077
1078 Writes data beginning at Lba:Offset from FV. The write terminates either
1079 when *NumBytes of data have been written, or when a block boundary is
1080 reached. *NumBytes is updated to reflect the actual number of bytes
1081 written. The write opertion does not include erase. This routine will
1082 attempt to write only the specified bytes. If the writes do not stick,
1083 it will return an error.
1084
1085 Arguments:
1086 This - Calling context
1087 Lba - Block in which to begin write
1088 Offset - Offset in the block at which to begin write
1089 NumBytes - On input, indicates the requested write size. On
1090 output, indicates the actual number of bytes written
1091 Buffer - Buffer containing source data for the write.
1092
1093 Returns:
1094 EFI_SUCCESS - The firmware volume was written successfully
1095 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1096 NumBytes contains the total number of bytes
1097 actually written
1098 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1099 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1100 could not be written
1101 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1102
1103 --*/
1104 {
1105
1106 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1107
1108 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1109
1110 return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1111 }
1112
1113 EFI_STATUS
1114 EFIAPI
1115 FvbProtocolRead (
1116 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1117 IN CONST EFI_LBA Lba,
1118 IN CONST UINTN Offset,
1119 IN OUT UINTN *NumBytes,
1120 IN UINT8 *Buffer
1121 )
1122 /*++
1123
1124 Routine Description:
1125
1126 Reads data beginning at Lba:Offset from FV. The Read terminates either
1127 when *NumBytes of data have been read, or when a block boundary is
1128 reached. *NumBytes is updated to reflect the actual number of bytes
1129 written. The write opertion does not include erase. This routine will
1130 attempt to write only the specified bytes. If the writes do not stick,
1131 it will return an error.
1132
1133 Arguments:
1134 This - Calling context
1135 Lba - Block in which to begin Read
1136 Offset - Offset in the block at which to begin Read
1137 NumBytes - On input, indicates the requested write size. On
1138 output, indicates the actual number of bytes Read
1139 Buffer - Buffer containing source data for the Read.
1140
1141 Returns:
1142 EFI_SUCCESS - The firmware volume was read successfully and
1143 contents are in Buffer
1144 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1145 NumBytes contains the total number of bytes returned
1146 in Buffer
1147 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1148 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1149 could not be read
1150 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1151
1152 --*/
1153 {
1154
1155 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1156
1157 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1158
1159 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1160 }
1161 //
1162 // FVB Extension Protocols
1163 //
1164 EFI_STATUS
1165 EFIAPI
1166 FvbExtendProtocolEraseCustomBlockRange (
1167 IN EFI_FVB_EXTENSION_PROTOCOL *This,
1168 IN EFI_LBA StartLba,
1169 IN UINTN OffsetStartLba,
1170 IN EFI_LBA LastLba,
1171 IN UINTN OffsetLastLba
1172 )
1173 /*++
1174
1175 Routine Description:
1176 Erases and initializes a specified range of a firmware volume
1177
1178 Arguments:
1179 This - Calling context
1180 StartLba - The starting logical block index to be erased
1181 OffsetStartLba - Offset into the starting block at which to
1182 begin erasing
1183 LastLba - The last logical block index to be erased
1184 OffsetStartLba - Offset into the last block at which to end erasing
1185
1186 Returns:
1187 EFI_SUCCESS - The firmware volume was erased successfully
1188 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1189 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1190 could not be written. Firmware device may have been
1191 partially erased
1192
1193 --*/
1194 {
1195 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1196
1197 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);
1198
1199 return FvbEraseCustomBlockRange (
1200 FvbDevice->Instance,
1201 StartLba,
1202 OffsetStartLba,
1203 LastLba,
1204 OffsetLastLba,
1205 mFvbModuleGlobal,
1206 EfiGoneVirtual ()
1207 );
1208 }
1209
1210 STATIC
1211 EFI_STATUS
1212 ValidateFvHeader (
1213 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
1214 )
1215 /*++
1216
1217 Routine Description:
1218 Check the integrity of firmware volume header
1219
1220 Arguments:
1221 FwVolHeader - A pointer to a firmware volume header
1222
1223 Returns:
1224 EFI_SUCCESS - The firmware volume is consistent
1225 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an FV
1226
1227 --*/
1228 {
1229 UINT16 *Ptr;
1230 UINT16 HeaderLength;
1231 UINT16 Checksum;
1232
1233 //
1234 // Verify the header revision, header signature, length
1235 // Length of FvBlock cannot be 2**64-1
1236 // HeaderLength cannot be an odd number
1237 //
1238 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1239 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1240 (FwVolHeader->FvLength == ((UINTN) -1)) ||
1241 ((FwVolHeader->HeaderLength & 0x01) != 0)
1242 ) {
1243 return EFI_NOT_FOUND;
1244 }
1245 //
1246 // Verify the header checksum
1247 //
1248 HeaderLength = (UINT16) (FwVolHeader->HeaderLength / 2);
1249 Ptr = (UINT16 *) FwVolHeader;
1250 Checksum = 0;
1251 while (HeaderLength > 0) {
1252 Checksum = Checksum + (*Ptr);
1253 HeaderLength--;
1254 Ptr++;
1255 }
1256
1257 if (Checksum != 0) {
1258 return EFI_NOT_FOUND;
1259 }
1260
1261 return EFI_SUCCESS;
1262 }
1263
1264 EFI_STATUS
1265 EFIAPI
1266 FvbInitialize (
1267 IN EFI_HANDLE ImageHandle,
1268 IN EFI_SYSTEM_TABLE *SystemTable
1269 )
1270 /*++
1271
1272 Routine Description:
1273 This function does common initialization for FVB services
1274
1275 Arguments:
1276
1277 Returns:
1278
1279 --*/
1280 {
1281 EFI_STATUS Status;
1282 EFI_FW_VOL_INSTANCE *FwhInstance;
1283 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
1284 EFI_DXE_SERVICES *DxeServices;
1285 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
1286 UINT32 BufferSize;
1287 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
1288 EFI_HANDLE FwbHandle;
1289 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1290 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *OldFwbInterface;
1291 EFI_DEVICE_PATH_PROTOCOL *TempFwbDevicePath;
1292 FV_DEVICE_PATH TempFvbDevicePathData;
1293 UINT32 MaxLbaSize;
1294 EFI_PHYSICAL_ADDRESS BaseAddress;
1295 UINT64 Length;
1296 UINTN NumOfBlocks;
1297 EFI_PEI_HOB_POINTERS FvHob;
1298
1299 //
1300 // Get the DXE services table
1301 //
1302 DxeServices = gDS;
1303
1304 //
1305 // Allocate runtime services data for global variable, which contains
1306 // the private data of all firmware volume block instances
1307 //
1308 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
1309 ASSERT (mFvbModuleGlobal != NULL);
1310
1311 //
1312 // Calculate the total size for all firmware volume block instances
1313 //
1314 BufferSize = 0;
1315
1316 FvHob.Raw = GetHobList ();
1317 while ((FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw)) != NULL) {
1318 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1319 Length = FvHob.FirmwareVolume->Length;
1320 //
1321 // Check if it is a "real" flash
1322 //
1323 Status = DxeServices->GetMemorySpaceDescriptor (
1324 BaseAddress,
1325 &Descriptor
1326 );
1327 if (EFI_ERROR (Status)) {
1328 break;
1329 }
1330
1331 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1332 FvHob.Raw = GET_NEXT_HOB (FvHob);
1333 continue;
1334 }
1335
1336 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1337 Status = ValidateFvHeader (FwVolHeader);
1338 if (EFI_ERROR (Status)) {
1339 //
1340 // Get FvbInfo
1341 //
1342 Status = GetFvbInfo (Length, &FwVolHeader);
1343 if (EFI_ERROR (Status)) {
1344 FvHob.Raw = GET_NEXT_HOB (FvHob);
1345 continue;
1346 }
1347 }
1348
1349 BufferSize += (sizeof (EFI_FW_VOL_INSTANCE) + FwVolHeader->HeaderLength - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1350 FvHob.Raw = GET_NEXT_HOB (FvHob);
1351 }
1352
1353 //
1354 // Only need to allocate once. There is only one copy of physical memory for
1355 // the private data of each FV instance. But in virtual mode or in physical
1356 // mode, the address of the the physical memory may be different.
1357 //
1358 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);
1359 ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);
1360
1361 //
1362 // Make a virtual copy of the FvInstance pointer.
1363 //
1364 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1365 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1366
1367 mFvbModuleGlobal->NumFv = 0;
1368 MaxLbaSize = 0;
1369
1370 FvHob.Raw = GetHobList ();
1371 while (NULL != (FvHob.Raw = GetNextHob (EFI_HOB_TYPE_FV, FvHob.Raw))) {
1372 BaseAddress = FvHob.FirmwareVolume->BaseAddress;
1373 Length = FvHob.FirmwareVolume->Length;
1374 //
1375 // Check if it is a "real" flash
1376 //
1377 Status = DxeServices->GetMemorySpaceDescriptor (
1378 BaseAddress,
1379 &Descriptor
1380 );
1381 if (EFI_ERROR (Status)) {
1382 break;
1383 }
1384
1385 if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeMemoryMappedIo) {
1386 FvHob.Raw = GET_NEXT_HOB (FvHob);
1387 continue;
1388 }
1389
1390 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
1391 Status = ValidateFvHeader (FwVolHeader);
1392 if (EFI_ERROR (Status)) {
1393 //
1394 // Get FvbInfo to provide in FwhInstance.
1395 //
1396 Status = GetFvbInfo (Length, &FwVolHeader);
1397 if (EFI_ERROR (Status)) {
1398 FvHob.Raw = GET_NEXT_HOB (FvHob);
1399 continue;
1400 }
1401 //
1402 // Write healthy FV header back.
1403 //
1404 CopyMem (
1405 (VOID *) (UINTN) BaseAddress,
1406 (VOID *) FwVolHeader,
1407 FwVolHeader->HeaderLength
1408 );
1409 }
1410
1411 FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1412 FwhInstance->FvBase[FVB_VIRTUAL] = (UINTN) BaseAddress;
1413
1414 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1415 FwVolHeader = &(FwhInstance->VolumeHeader);
1416 EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1417
1418 NumOfBlocks = 0;
1419
1420 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1421 //
1422 // Get the maximum size of a block. The size will be used to allocate
1423 // buffer for Scratch space, the intermediate buffer for FVB extension
1424 // protocol
1425 //
1426 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1427 MaxLbaSize = PtrBlockMapEntry->Length;
1428 }
1429
1430 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1431 }
1432 //
1433 // The total number of blocks in the FV.
1434 //
1435 FwhInstance->NumOfBlocks = NumOfBlocks;
1436
1437 //
1438 // Add a FVB Protocol Instance
1439 //
1440 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1441 ASSERT (FvbDevice != NULL);
1442
1443 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1444
1445 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1446 mFvbModuleGlobal->NumFv++;
1447
1448 //
1449 // Set up the devicepath
1450 //
1451 FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1452 FvbDevice->DevicePath.MemMapDevPath.EndingAddress = BaseAddress + (FwVolHeader->FvLength - 1);
1453
1454 //
1455 // Find a handle with a matching device path that has supports FW Block protocol
1456 //
1457 TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1458 CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1459 Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1460 if (EFI_ERROR (Status)) {
1461 //
1462 // LocateDevicePath fails so install a new interface and device path
1463 //
1464 FwbHandle = NULL;
1465 Status = gBS->InstallMultipleProtocolInterfaces (
1466 &FwbHandle,
1467 &gEfiFirmwareVolumeBlockProtocolGuid,
1468 &FvbDevice->FwVolBlockInstance,
1469 &gEfiDevicePathProtocolGuid,
1470 &FvbDevice->DevicePath,
1471 NULL
1472 );
1473 ASSERT_EFI_ERROR (Status);
1474 } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {
1475 //
1476 // Device allready exists, so reinstall the FVB protocol
1477 //
1478 Status = gBS->HandleProtocol (
1479 FwbHandle,
1480 &gEfiFirmwareVolumeBlockProtocolGuid,
1481 &OldFwbInterface
1482 );
1483 ASSERT_EFI_ERROR (Status);
1484
1485 Status = gBS->ReinstallProtocolInterface (
1486 FwbHandle,
1487 &gEfiFirmwareVolumeBlockProtocolGuid,
1488 OldFwbInterface,
1489 &FvbDevice->FwVolBlockInstance
1490 );
1491 ASSERT_EFI_ERROR (Status);
1492
1493 } else {
1494 //
1495 // There was a FVB protocol on an End Device Path node
1496 //
1497 ASSERT (FALSE);
1498 }
1499 //
1500 // Install FVB Extension Protocol on the same handle
1501 //
1502 Status = gBS->InstallMultipleProtocolInterfaces (
1503 &FwbHandle,
1504 &gEfiFvbExtensionProtocolGuid,
1505 &FvbDevice->FvbExtension,
1506 &gEfiAlternateFvBlockGuid,
1507 NULL,
1508 NULL
1509 );
1510
1511 ASSERT_EFI_ERROR (Status);
1512
1513 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1514 (
1515 (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1516 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1517 );
1518
1519 FvHob.Raw = GET_NEXT_HOB (FvHob);
1520 }
1521
1522 //
1523 // Allocate for scratch space, an intermediate buffer for FVB extention
1524 //
1525 mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimePool (MaxLbaSize);
1526 ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] != NULL);
1527
1528 mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
1529
1530 return EFI_SUCCESS;
1531 }