]> git.proxmox.com Git - mirror_edk2.git/blob - Nt32Pkg/FvbServicesRuntimeDxe/FWBlockService.c
Clean up to update the reference of the these macros:
[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 #include <Library/DevicePathLib.h>
49
50 #include "FWBlockService.h"
51
52 #define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
53
54 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
55
56 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
57 FVB_DEVICE_SIGNATURE,
58 {
59 {
60 {
61 HARDWARE_DEVICE_PATH,
62 HW_MEMMAP_DP,
63 {
64 sizeof (MEMMAP_DEVICE_PATH),
65 0
66 }
67 },
68 EfiMemoryMappedIO,
69 0,
70 0,
71 },
72 {
73 END_DEVICE_PATH_TYPE,
74 END_ENTIRE_DEVICE_PATH_SUBTYPE,
75 {
76 sizeof (EFI_DEVICE_PATH_PROTOCOL),
77 0
78 }
79 }
80 },
81 0,
82 {
83 FvbProtocolGetAttributes,
84 FvbProtocolSetAttributes,
85 FvbProtocolGetPhysicalAddress,
86 FvbProtocolGetBlockSize,
87 FvbProtocolRead,
88 FvbProtocolWrite,
89 FvbProtocolEraseBlocks,
90 NULL
91 },
92 {
93 FvbExtendProtocolEraseCustomBlockRange
94 }
95 };
96
97
98
99 VOID
100 EFIAPI
101 FvbVirtualddressChangeEvent (
102 IN EFI_EVENT Event,
103 IN VOID *Context
104 )
105 /*++
106
107 Routine Description:
108
109 Fixup internal data so that EFI and SAL can be call in virtual mode.
110 Call the passed in Child Notify event and convert the mFvbModuleGlobal
111 date items to there virtual address.
112
113 mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] - Physical copy of instance data
114 mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] - Virtual pointer to common
115 instance data.
116
117 Arguments:
118
119 (Standard EFI notify event - EFI_EVENT_NOTIFY)
120
121 Returns:
122
123 None
124
125 --*/
126 {
127 EFI_FW_VOL_INSTANCE *FwhInstance;
128 UINTN Index;
129
130 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
131
132 //
133 // Convert the base address of all the instances
134 //
135 Index = 0;
136 FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
137 while (Index < mFvbModuleGlobal->NumFv) {
138 EfiConvertPointer (0x0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
139 FwhInstance = (EFI_FW_VOL_INSTANCE *)
140 (
141 (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
142 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
143 );
144 Index++;
145 }
146
147 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
148 EfiConvertPointer (0x0, (VOID **) &mFvbModuleGlobal);
149 }
150
151 EFI_STATUS
152 GetFvbInstance (
153 IN UINTN Instance,
154 IN ESAL_FWB_GLOBAL *Global,
155 OUT EFI_FW_VOL_INSTANCE **FwhInstance,
156 IN BOOLEAN Virtual
157 )
158 /*++
159
160 Routine Description:
161 Retrieves the physical address of a memory mapped FV
162
163 Arguments:
164 Instance - The FV instance whose base address is going to be
165 returned
166 Global - Pointer to ESAL_FWB_GLOBAL that contains all
167 instance data
168 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
169 Virtual - Whether CPU is in virtual or physical mode
170
171 Returns:
172 EFI_SUCCESS - Successfully returns
173 EFI_INVALID_PARAMETER - Instance not found
174
175 --*/
176 {
177 EFI_FW_VOL_INSTANCE *FwhRecord;
178
179 if (Instance >= Global->NumFv) {
180 return EFI_INVALID_PARAMETER;
181 }
182 //
183 // Find the right instance of the FVB private data
184 //
185 FwhRecord = Global->FvInstance[Virtual];
186 while (Instance > 0) {
187 FwhRecord = (EFI_FW_VOL_INSTANCE *)
188 (
189 (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
190 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
191 );
192 Instance--;
193 }
194
195 *FwhInstance = FwhRecord;
196
197 return EFI_SUCCESS;
198 }
199
200 EFI_STATUS
201 FvbGetPhysicalAddress (
202 IN UINTN Instance,
203 OUT EFI_PHYSICAL_ADDRESS *Address,
204 IN ESAL_FWB_GLOBAL *Global,
205 IN BOOLEAN Virtual
206 )
207 /*++
208
209 Routine Description:
210 Retrieves the physical address of a memory mapped FV
211
212 Arguments:
213 Instance - The FV instance whose base address is going to be
214 returned
215 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
216 that on successful return, contains the base address
217 of the firmware volume.
218 Global - Pointer to ESAL_FWB_GLOBAL that contains all
219 instance data
220 Virtual - Whether CPU is in virtual or physical mode
221
222 Returns:
223 EFI_SUCCESS - Successfully returns
224 EFI_INVALID_PARAMETER - Instance not found
225
226 --*/
227 {
228 EFI_FW_VOL_INSTANCE *FwhInstance;
229 EFI_STATUS Status;
230
231 //
232 // Find the right instance of the FVB private data
233 //
234 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
235 ASSERT_EFI_ERROR (Status);
236 *Address = FwhInstance->FvBase[Virtual];
237
238 return EFI_SUCCESS;
239 }
240
241 EFI_STATUS
242 FvbGetVolumeAttributes (
243 IN UINTN Instance,
244 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
245 IN ESAL_FWB_GLOBAL *Global,
246 IN BOOLEAN Virtual
247 )
248 /*++
249
250 Routine Description:
251 Retrieves attributes, insures positive polarity of attribute bits, returns
252 resulting attributes in output parameter
253
254 Arguments:
255 Instance - The FV instance whose attributes is going to be
256 returned
257 Attributes - Output buffer which contains attributes
258 Global - Pointer to ESAL_FWB_GLOBAL that contains all
259 instance data
260 Virtual - Whether CPU is in virtual or physical mode
261
262 Returns:
263 EFI_SUCCESS - Successfully returns
264 EFI_INVALID_PARAMETER - Instance not found
265
266 --*/
267 {
268 EFI_FW_VOL_INSTANCE *FwhInstance;
269 EFI_STATUS Status;
270
271 //
272 // Find the right instance of the FVB private data
273 //
274 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
275 ASSERT_EFI_ERROR (Status);
276 *Attributes = FwhInstance->VolumeHeader.Attributes;
277
278 return EFI_SUCCESS;
279 }
280
281 EFI_STATUS
282 FvbGetLbaAddress (
283 IN UINTN Instance,
284 IN EFI_LBA Lba,
285 OUT UINTN *LbaAddress,
286 OUT UINTN *LbaLength,
287 OUT UINTN *NumOfBlocks,
288 IN ESAL_FWB_GLOBAL *Global,
289 IN BOOLEAN Virtual
290 )
291 /*++
292
293 Routine Description:
294 Retrieves the starting address of an LBA in an FV
295
296 Arguments:
297 Instance - The FV instance which the Lba belongs to
298 Lba - The logical block address
299 LbaAddress - On output, contains the physical starting address
300 of the Lba
301 LbaLength - On output, contains the length of the block
302 NumOfBlocks - A pointer to a caller allocated UINTN in which the
303 number of consecutive blocks starting with Lba is
304 returned. All blocks in this range have a size of
305 BlockSize
306 Global - Pointer to ESAL_FWB_GLOBAL that contains all
307 instance data
308 Virtual - Whether CPU is in virtual or physical mode
309
310 Returns:
311 EFI_SUCCESS - Successfully returns
312 EFI_INVALID_PARAMETER - Instance not found
313
314 --*/
315 {
316 UINT32 NumBlocks;
317 UINT32 BlockLength;
318 UINTN Offset;
319 EFI_LBA StartLba;
320 EFI_LBA NextLba;
321 EFI_FW_VOL_INSTANCE *FwhInstance;
322 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
323 EFI_STATUS Status;
324
325 //
326 // Find the right instance of the FVB private data
327 //
328 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
329 ASSERT_EFI_ERROR (Status);
330
331 StartLba = 0;
332 Offset = 0;
333 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
334
335 //
336 // Parse the blockmap of the FV to find which map entry the Lba belongs to
337 //
338 while (TRUE) {
339 NumBlocks = BlockMap->NumBlocks;
340 BlockLength = BlockMap->Length;
341
342 if (NumBlocks == 0 || BlockLength == 0) {
343 return EFI_INVALID_PARAMETER;
344 }
345
346 NextLba = StartLba + NumBlocks;
347
348 //
349 // The map entry found
350 //
351 if (Lba >= StartLba && Lba < NextLba) {
352 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
353 if (LbaAddress != NULL) {
354 *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
355 }
356
357 if (LbaLength != NULL) {
358 *LbaLength = BlockLength;
359 }
360
361 if (NumOfBlocks != NULL) {
362 *NumOfBlocks = (UINTN) (NextLba - Lba);
363 }
364
365 return EFI_SUCCESS;
366 }
367
368 StartLba = NextLba;
369 Offset = Offset + NumBlocks * BlockLength;
370 BlockMap++;
371 }
372 }
373
374 EFI_STATUS
375 FvbReadBlock (
376 IN UINTN Instance,
377 IN EFI_LBA Lba,
378 IN UINTN BlockOffset,
379 IN OUT UINTN *NumBytes,
380 IN UINT8 *Buffer,
381 IN ESAL_FWB_GLOBAL *Global,
382 IN BOOLEAN Virtual
383 )
384 /*++
385
386 Routine Description:
387 Reads specified number of bytes into a buffer from the specified block
388
389 Arguments:
390 Instance - The FV instance to be read from
391 Lba - The logical block address to be read from
392 BlockOffset - Offset into the block at which to begin reading
393 NumBytes - Pointer that on input contains the total size of
394 the buffer. On output, it contains the total number
395 of bytes read
396 Buffer - Pointer to a caller allocated buffer that will be
397 used to hold the data read
398 Global - Pointer to ESAL_FWB_GLOBAL that contains all
399 instance data
400 Virtual - Whether CPU is in virtual or physical mode
401
402 Returns:
403 EFI_SUCCESS - The firmware volume was read successfully and
404 contents are in Buffer
405 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
406 NumBytes contains the total number of bytes returned
407 in Buffer
408 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
409 EFI_DEVICE_ERROR - The block device is not functioning correctly and
410 could not be read
411 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
412
413 --*/
414 {
415 EFI_FVB_ATTRIBUTES_2 Attributes;
416 UINTN LbaAddress;
417 UINTN LbaLength;
418 EFI_STATUS Status;
419
420 //
421 // Check for invalid conditions
422 //
423 if ((NumBytes == NULL) || (Buffer == NULL)) {
424 return EFI_INVALID_PARAMETER;
425 }
426
427 if (*NumBytes == 0) {
428 return EFI_INVALID_PARAMETER;
429 }
430
431 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
432 if (EFI_ERROR (Status)) {
433 return Status;
434 }
435 //
436 // Check if the FV is read enabled
437 //
438 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
439
440 if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
441 return EFI_ACCESS_DENIED;
442 }
443 //
444 // Perform boundary checks and adjust NumBytes
445 //
446 if (BlockOffset > LbaLength) {
447 return EFI_INVALID_PARAMETER;
448 }
449
450 if (LbaLength < (*NumBytes + BlockOffset)) {
451 *NumBytes = (UINT32) (LbaLength - BlockOffset);
452 Status = EFI_BAD_BUFFER_SIZE;
453 }
454
455 CopyMem (Buffer, (UINT8 *) (LbaAddress + BlockOffset), (UINTN) (*NumBytes));
456
457 return Status;
458 }
459
460 EFI_STATUS
461 FvbWriteBlock (
462 IN UINTN Instance,
463 IN EFI_LBA Lba,
464 IN UINTN BlockOffset,
465 IN OUT UINTN *NumBytes,
466 IN UINT8 *Buffer,
467 IN ESAL_FWB_GLOBAL *Global,
468 IN BOOLEAN Virtual
469 )
470 /*++
471
472 Routine Description:
473 Writes specified number of bytes from the input buffer to the block
474
475 Arguments:
476 Instance - The FV instance to be written to
477 Lba - The starting logical block index to write to
478 BlockOffset - Offset into the block at which to begin writing
479 NumBytes - Pointer that on input contains the total size of
480 the buffer. On output, it contains the total number
481 of bytes actually written
482 Buffer - Pointer to a caller allocated buffer that contains
483 the source for the write
484 Global - Pointer to ESAL_FWB_GLOBAL that contains all
485 instance data
486 Virtual - Whether CPU is in virtual or physical mode
487
488 Returns:
489 EFI_SUCCESS - The firmware volume was written successfully
490 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
491 NumBytes contains the total number of bytes
492 actually written
493 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
494 EFI_DEVICE_ERROR - The block device is not functioning correctly and
495 could not be written
496 EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
497
498 --*/
499 {
500 EFI_FVB_ATTRIBUTES_2 Attributes;
501 UINTN LbaAddress;
502 UINTN LbaLength;
503 EFI_STATUS Status;
504
505 //
506 // Check for invalid conditions
507 //
508 if ((NumBytes == NULL) || (Buffer == NULL)) {
509 return EFI_INVALID_PARAMETER;
510 }
511
512 if (*NumBytes == 0) {
513 return EFI_INVALID_PARAMETER;
514 }
515
516 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
517 if (EFI_ERROR (Status)) {
518 return Status;
519 }
520 //
521 // Check if the FV is write enabled
522 //
523 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
524
525 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
526 return EFI_ACCESS_DENIED;
527 }
528 //
529 // Perform boundary checks and adjust NumBytes
530 //
531 if (BlockOffset > LbaLength) {
532 return EFI_INVALID_PARAMETER;
533 }
534
535 if (LbaLength < (*NumBytes + BlockOffset)) {
536 *NumBytes = (UINT32) (LbaLength - BlockOffset);
537 Status = EFI_BAD_BUFFER_SIZE;
538 }
539 //
540 // Write data
541 //
542 CopyMem ((UINT8 *) (LbaAddress + BlockOffset), Buffer, (UINTN) (*NumBytes));
543
544 return Status;
545 }
546
547 EFI_STATUS
548 FvbEraseBlock (
549 IN UINTN Instance,
550 IN EFI_LBA Lba,
551 IN ESAL_FWB_GLOBAL *Global,
552 IN BOOLEAN Virtual
553 )
554 /*++
555
556 Routine Description:
557 Erases and initializes a firmware volume block
558
559 Arguments:
560 Instance - The FV instance to be erased
561 Lba - The logical block index to be erased
562 Global - Pointer to ESAL_FWB_GLOBAL that contains all
563 instance data
564 Virtual - Whether CPU is in virtual or physical mode
565
566 Returns:
567 EFI_SUCCESS - The erase request was successfully completed
568 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
569 EFI_DEVICE_ERROR - The block device is not functioning correctly and
570 could not be written. Firmware device may have been
571 partially erased
572 EFI_INVALID_PARAMETER - Instance not found
573
574 --*/
575 {
576
577 EFI_FVB_ATTRIBUTES_2 Attributes;
578 UINTN LbaAddress;
579 UINTN LbaLength;
580 EFI_STATUS Status;
581 UINT8 Data;
582
583 //
584 // Check if the FV is write enabled
585 //
586 FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
587
588 if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
589 return EFI_ACCESS_DENIED;
590 }
591 //
592 // Get the starting address of the block for erase.
593 //
594 Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
595
596 if (EFI_ERROR (Status)) {
597 return Status;
598 }
599
600 if ((Attributes & EFI_FVB2_ERASE_POLARITY) != 0) {
601 Data = 0xFF;
602 } else {
603 Data = 0x0;
604 }
605
606 SetMem ((UINT8 *) LbaAddress, LbaLength, Data);
607
608 return EFI_SUCCESS;
609 }
610
611 EFI_STATUS
612 FvbEraseCustomBlockRange (
613 IN UINTN Instance,
614 IN EFI_LBA StartLba,
615 IN UINTN OffsetStartLba,
616 IN EFI_LBA LastLba,
617 IN UINTN OffsetLastLba,
618 IN ESAL_FWB_GLOBAL *Global,
619 IN BOOLEAN Virtual
620 )
621 /*++
622
623 Routine Description:
624 Erases and initializes a specified range of a firmware volume
625
626 Arguments:
627 Instance - The FV instance to be erased
628 StartLba - The starting logical block index to be erased
629 OffsetStartLba - Offset into the starting block at which to
630 begin erasing
631 LastLba - The last logical block index to be erased
632 OffsetStartLba - Offset into the last block at which to end erasing
633 Global - Pointer to ESAL_FWB_GLOBAL that contains all
634 instance data
635 Virtual - Whether CPU is in virtual or physical mode
636
637 Returns:
638 EFI_SUCCESS - The firmware volume was erased successfully
639 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
640 EFI_DEVICE_ERROR - The block device is not functioning correctly and
641 could not be written. Firmware device may have been
642 partially erased
643 EFI_INVALID_PARAMETER - Instance not found
644
645 --*/
646 {
647 EFI_LBA Index;
648 UINTN LbaSize;
649 UINTN ScratchLbaSizeData;
650 EFI_STATUS Status;
651
652 //
653 // First LBA
654 //
655 Status = FvbGetLbaAddress (Instance, StartLba, NULL, &LbaSize, NULL, Global, Virtual);
656 if (EFI_ERROR (Status)) {
657 return Status;
658 }
659
660 //
661 // Use the scratch space as the intermediate buffer to transfer data
662 // Back up the first LBA in scratch space.
663 //
664 FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
665
666 //
667 // erase now
668 //
669 FvbEraseBlock (Instance, StartLba, Global, Virtual);
670 ScratchLbaSizeData = OffsetStartLba;
671
672 //
673 // write the data back to the first block
674 //
675 if (ScratchLbaSizeData > 0) {
676 Status = FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);
677 if (EFI_ERROR (Status)) {
678 return Status;
679 }
680 }
681 //
682 // Middle LBAs
683 //
684 if (LastLba > (StartLba + 1)) {
685 for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {
686 FvbEraseBlock (Instance, Index, Global, Virtual);
687 }
688 }
689 //
690 // Last LBAs, the same as first LBAs
691 //
692 if (LastLba > StartLba) {
693 Status = FvbGetLbaAddress (Instance, LastLba, NULL, &LbaSize, NULL, Global, Virtual);
694 if (EFI_ERROR (Status)) {
695 return Status;
696 }
697 FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
698 FvbEraseBlock (Instance, LastLba, Global, Virtual);
699 }
700
701 ScratchLbaSizeData = LbaSize - (OffsetLastLba + 1);
702
703 if (ScratchLbaSizeData > 0) {
704 Status = FvbWriteBlock (
705 Instance,
706 LastLba,
707 (OffsetLastLba + 1),
708 &ScratchLbaSizeData,
709 Global->FvbScratchSpace[Virtual] + OffsetLastLba + 1,
710 Global,
711 Virtual
712 );
713 }
714
715 return Status;
716 }
717
718 EFI_STATUS
719 FvbSetVolumeAttributes (
720 IN UINTN Instance,
721 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
722 IN ESAL_FWB_GLOBAL *Global,
723 IN BOOLEAN Virtual
724 )
725 /*++
726
727 Routine Description:
728 Modifies the current settings of the firmware volume according to the
729 input parameter, and returns the new setting of the volume
730
731 Arguments:
732 Instance - The FV instance whose attributes is going to be
733 modified
734 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
735 containing the desired firmware volume settings.
736 On successful return, it contains the new settings
737 of the firmware volume
738 Global - Pointer to ESAL_FWB_GLOBAL that contains all
739 instance data
740 Virtual - Whether CPU is in virtual or physical mode
741
742 Returns:
743 EFI_SUCCESS - Successfully returns
744 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
745 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
746 in conflict with the capabilities as declared in the
747 firmware volume header
748
749 --*/
750 {
751 EFI_FW_VOL_INSTANCE *FwhInstance;
752 EFI_FVB_ATTRIBUTES_2 OldAttributes;
753 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
754 UINT32 Capabilities;
755 UINT32 OldStatus;
756 UINT32 NewStatus;
757 EFI_STATUS Status;
758 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
759
760 //
761 // Find the right instance of the FVB private data
762 //
763 Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
764 ASSERT_EFI_ERROR (Status);
765
766 AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
767 OldAttributes = *AttribPtr;
768 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
769 EFI_FVB2_READ_ENABLED_CAP | \
770 EFI_FVB2_WRITE_DISABLED_CAP | \
771 EFI_FVB2_WRITE_ENABLED_CAP | \
772 EFI_FVB2_LOCK_CAP \
773 );
774 OldStatus = OldAttributes & EFI_FVB2_STATUS;
775 NewStatus = *Attributes & EFI_FVB2_STATUS;
776
777 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
778 EFI_FVB2_READ_ENABLED_CAP | \
779 EFI_FVB2_WRITE_DISABLED_CAP | \
780 EFI_FVB2_WRITE_ENABLED_CAP | \
781 EFI_FVB2_LOCK_CAP | \
782 EFI_FVB2_STICKY_WRITE | \
783 EFI_FVB2_MEMORY_MAPPED | \
784 EFI_FVB2_ERASE_POLARITY | \
785 EFI_FVB2_READ_LOCK_CAP | \
786 EFI_FVB2_WRITE_LOCK_CAP | \
787 EFI_FVB2_ALIGNMENT;
788
789 //
790 // Some attributes of FV is read only can *not* be set
791 //
792 if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
793 return EFI_INVALID_PARAMETER;
794 }
795 //
796 // If firmware volume is locked, no status bit can be updated
797 //
798 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
799 if (OldStatus ^ NewStatus) {
800 return EFI_ACCESS_DENIED;
801 }
802 }
803 //
804 // Test read disable
805 //
806 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
807 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
808 return EFI_INVALID_PARAMETER;
809 }
810 }
811 //
812 // Test read enable
813 //
814 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
815 if (NewStatus & EFI_FVB2_READ_STATUS) {
816 return EFI_INVALID_PARAMETER;
817 }
818 }
819 //
820 // Test write disable
821 //
822 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
823 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
824 return EFI_INVALID_PARAMETER;
825 }
826 }
827 //
828 // Test write enable
829 //
830 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
831 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
832 return EFI_INVALID_PARAMETER;
833 }
834 }
835 //
836 // Test lock
837 //
838 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
839 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
840 return EFI_INVALID_PARAMETER;
841 }
842 }
843
844 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
845 *AttribPtr = (*AttribPtr) | NewStatus;
846 *Attributes = *AttribPtr;
847
848 return EFI_SUCCESS;
849 }
850 //
851 // FVB protocol APIs
852 //
853 EFI_STATUS
854 EFIAPI
855 FvbProtocolGetPhysicalAddress (
856 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
857 OUT EFI_PHYSICAL_ADDRESS *Address
858 )
859 /*++
860
861 Routine Description:
862
863 Retrieves the physical address of the device.
864
865 Arguments:
866
867 This - Calling context
868 Address - Output buffer containing the address.
869
870 Returns:
871
872 Returns:
873 EFI_SUCCESS - Successfully returns
874
875 --*/
876 {
877 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
878
879 FvbDevice = FVB_DEVICE_FROM_THIS (This);
880
881 return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
882 }
883
884 EFI_STATUS
885 EFIAPI
886 FvbProtocolGetBlockSize (
887 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
888 IN CONST EFI_LBA Lba,
889 OUT UINTN *BlockSize,
890 OUT UINTN *NumOfBlocks
891 )
892 /*++
893
894 Routine Description:
895 Retrieve the size of a logical block
896
897 Arguments:
898 This - Calling context
899 Lba - Indicates which block to return the size for.
900 BlockSize - A pointer to a caller allocated UINTN in which
901 the size of the block is returned
902 NumOfBlocks - a pointer to a caller allocated UINTN in which the
903 number of consecutive blocks starting with Lba is
904 returned. All blocks in this range have a size of
905 BlockSize
906
907 Returns:
908 EFI_SUCCESS - The firmware volume was read successfully and
909 contents are in Buffer
910
911 --*/
912 {
913 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
914
915 FvbDevice = FVB_DEVICE_FROM_THIS (This);
916
917 return FvbGetLbaAddress (
918 FvbDevice->Instance,
919 Lba,
920 NULL,
921 BlockSize,
922 NumOfBlocks,
923 mFvbModuleGlobal,
924 EfiGoneVirtual ()
925 );
926 }
927
928 EFI_STATUS
929 EFIAPI
930 FvbProtocolGetAttributes (
931 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
932 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
933 )
934 /*++
935
936 Routine Description:
937 Retrieves Volume attributes. No polarity translations are done.
938
939 Arguments:
940 This - Calling context
941 Attributes - output buffer which contains attributes
942
943 Returns:
944 EFI_SUCCESS - Successfully returns
945
946 --*/
947 {
948 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
949
950 FvbDevice = FVB_DEVICE_FROM_THIS (This);
951
952 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
953 }
954
955 EFI_STATUS
956 EFIAPI
957 FvbProtocolSetAttributes (
958 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
959 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
960 )
961 /*++
962
963 Routine Description:
964 Sets Volume attributes. No polarity translations are done.
965
966 Arguments:
967 This - Calling context
968 Attributes - output buffer which contains attributes
969
970 Returns:
971 EFI_SUCCESS - Successfully returns
972
973 --*/
974 {
975 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
976
977 FvbDevice = FVB_DEVICE_FROM_THIS (This);
978
979 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
980 }
981
982 EFI_STATUS
983 EFIAPI
984 FvbProtocolEraseBlocks (
985 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
986 ...
987 )
988 /*++
989
990 Routine Description:
991
992 The EraseBlock() function erases one or more blocks as denoted by the
993 variable argument list. The entire parameter list of blocks must be verified
994 prior to erasing any blocks. If a block is requested that does not exist
995 within the associated firmware volume (it has a larger index than the last
996 block of the firmware volume), the EraseBlock() function must return
997 EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
998
999 Arguments:
1000 This - Calling context
1001 ... - Starting LBA followed by Number of Lba to erase.
1002 a -1 to terminate the list.
1003
1004 Returns:
1005 EFI_SUCCESS - The erase request was successfully completed
1006 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1007 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1008 could not be written. Firmware device may have been
1009 partially erased
1010
1011 --*/
1012 {
1013 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1014 EFI_FW_VOL_INSTANCE *FwhInstance;
1015 UINTN NumOfBlocks;
1016 VA_LIST args;
1017 EFI_LBA StartingLba;
1018 UINTN NumOfLba;
1019 EFI_STATUS Status;
1020
1021 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1022
1023 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
1024 ASSERT_EFI_ERROR (Status);
1025
1026 NumOfBlocks = FwhInstance->NumOfBlocks;
1027
1028 VA_START (args, This);
1029
1030 do {
1031 StartingLba = VA_ARG (args, EFI_LBA);
1032 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1033 break;
1034 }
1035
1036 NumOfLba = VA_ARG (args, UINT32);
1037
1038 //
1039 // Check input parameters
1040 //
1041 if (NumOfLba == 0) {
1042 VA_END (args);
1043 return EFI_INVALID_PARAMETER;
1044 }
1045
1046 if ((StartingLba + NumOfLba) > NumOfBlocks) {
1047 return EFI_INVALID_PARAMETER;
1048 }
1049 } while (1);
1050
1051 VA_END (args);
1052
1053 VA_START (args, This);
1054 do {
1055 StartingLba = VA_ARG (args, EFI_LBA);
1056 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1057 break;
1058 }
1059
1060 NumOfLba = VA_ARG (args, UINT32);
1061
1062 while (NumOfLba > 0) {
1063 Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
1064 if (EFI_ERROR (Status)) {
1065 VA_END (args);
1066 return Status;
1067 }
1068
1069 StartingLba++;
1070 NumOfLba--;
1071 }
1072
1073 } while (1);
1074
1075 VA_END (args);
1076
1077 return EFI_SUCCESS;
1078 }
1079
1080 EFI_STATUS
1081 EFIAPI
1082 FvbProtocolWrite (
1083 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1084 IN EFI_LBA Lba,
1085 IN UINTN Offset,
1086 IN OUT UINTN *NumBytes,
1087 IN UINT8 *Buffer
1088 )
1089 /*++
1090
1091 Routine Description:
1092
1093 Writes data beginning at Lba:Offset from FV. The write terminates either
1094 when *NumBytes of data have been written, or when a block boundary is
1095 reached. *NumBytes is updated to reflect the actual number of bytes
1096 written. The write opertion does not include erase. This routine will
1097 attempt to write only the specified bytes. If the writes do not stick,
1098 it will return an error.
1099
1100 Arguments:
1101 This - Calling context
1102 Lba - Block in which to begin write
1103 Offset - Offset in the block at which to begin write
1104 NumBytes - On input, indicates the requested write size. On
1105 output, indicates the actual number of bytes written
1106 Buffer - Buffer containing source data for the write.
1107
1108 Returns:
1109 EFI_SUCCESS - The firmware volume was written successfully
1110 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
1111 NumBytes contains the total number of bytes
1112 actually written
1113 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1114 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1115 could not be written
1116 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1117
1118 --*/
1119 {
1120
1121 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1122
1123 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1124
1125 return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1126 }
1127
1128 EFI_STATUS
1129 EFIAPI
1130 FvbProtocolRead (
1131 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
1132 IN CONST EFI_LBA Lba,
1133 IN CONST UINTN Offset,
1134 IN OUT UINTN *NumBytes,
1135 IN UINT8 *Buffer
1136 )
1137 /*++
1138
1139 Routine Description:
1140
1141 Reads data beginning at Lba:Offset from FV. The Read terminates either
1142 when *NumBytes of data have been read, or when a block boundary is
1143 reached. *NumBytes is updated to reflect the actual number of bytes
1144 written. The write opertion does not include erase. This routine will
1145 attempt to write only the specified bytes. If the writes do not stick,
1146 it will return an error.
1147
1148 Arguments:
1149 This - Calling context
1150 Lba - Block in which to begin Read
1151 Offset - Offset in the block at which to begin Read
1152 NumBytes - On input, indicates the requested write size. On
1153 output, indicates the actual number of bytes Read
1154 Buffer - Buffer containing source data for the Read.
1155
1156 Returns:
1157 EFI_SUCCESS - The firmware volume was read successfully and
1158 contents are in Buffer
1159 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
1160 NumBytes contains the total number of bytes returned
1161 in Buffer
1162 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
1163 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1164 could not be read
1165 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1166
1167 --*/
1168 {
1169
1170 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1171
1172 FvbDevice = FVB_DEVICE_FROM_THIS (This);
1173
1174 return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1175 }
1176 //
1177 // FVB Extension Protocols
1178 //
1179 EFI_STATUS
1180 EFIAPI
1181 FvbExtendProtocolEraseCustomBlockRange (
1182 IN EFI_FVB_EXTENSION_PROTOCOL *This,
1183 IN EFI_LBA StartLba,
1184 IN UINTN OffsetStartLba,
1185 IN EFI_LBA LastLba,
1186 IN UINTN OffsetLastLba
1187 )
1188 /*++
1189
1190 Routine Description:
1191 Erases and initializes a specified range of a firmware volume
1192
1193 Arguments:
1194 This - Calling context
1195 StartLba - The starting logical block index to be erased
1196 OffsetStartLba - Offset into the starting block at which to
1197 begin erasing
1198 LastLba - The last logical block index to be erased
1199 OffsetStartLba - Offset into the last block at which to end erasing
1200
1201 Returns:
1202 EFI_SUCCESS - The firmware volume was erased successfully
1203 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
1204 EFI_DEVICE_ERROR - The block device is not functioning correctly and
1205 could not be written. Firmware device may have been
1206 partially erased
1207
1208 --*/
1209 {
1210 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1211
1212 FvbDevice = FVB_EXTEND_DEVICE_FROM_THIS (This);
1213
1214 return FvbEraseCustomBlockRange (
1215 FvbDevice->Instance,
1216 StartLba,
1217 OffsetStartLba,
1218 LastLba,
1219 OffsetLastLba,
1220 mFvbModuleGlobal,
1221 EfiGoneVirtual ()
1222 );
1223 }
1224
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 = (UINT16)(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 (IsDevicePathEnd (TempFwbDevicePath)) {
1489 //
1490 // Device allready exists, so reinstall the FVB protocol
1491 //
1492 Status = gBS->HandleProtocol (
1493 FwbHandle,
1494 &gEfiFirmwareVolumeBlockProtocolGuid,
1495 (VOID**)&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 }