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