1 /**@file
2
3 Copyright (c) 2019, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
4 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
5
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 Module Name:
9
10 FWBlockService.c
11
12 Abstract:
13
14 Revision History
15
16 **/
17
18 //
19 // The protocols, PPI and GUID defintions for this module
20 //
21 #include <Protocol/DevicePath.h>
22 #include <Protocol/FirmwareVolumeBlock.h>
23
24 //
25 // The Library classes this module consumes
26 //
27 #include <Library/BaseLib.h>
FixEthernetAliases(VOID)28 #include <Library/BaseMemoryLib.h>
29 #include <Library/DebugLib.h>
30 #include <Library/DevicePathLib.h>
31 #include <Library/DxeServicesTableLib.h>
32 #include <Library/MemoryAllocationLib.h>
33 #include <Library/UefiBootServicesTableLib.h>
34
35 #include "FwBlockService.h"
36 #include "RamFlash.h"
37
38 #define EFI_FVB2_STATUS \
39 (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
40
41 ESAL_FWB_GLOBAL *mFvbModuleGlobal;
42
43 FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {
44 {
45 {
46 HARDWARE_DEVICE_PATH,
47 HW_MEMMAP_DP,
48 {
49 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
50 (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
51 }
52 },
53 EfiMemoryMappedIO,
54 (EFI_PHYSICAL_ADDRESS) 0,
55 (EFI_PHYSICAL_ADDRESS) 0,
56 },
57 {
58 END_DEVICE_PATH_TYPE,
59 END_ENTIRE_DEVICE_PATH_SUBTYPE,
60 {
61 END_DEVICE_PATH_LENGTH,
62 0
63 }
64 }
65 };
66
67 FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {
68 {
69 {
70 MEDIA_DEVICE_PATH,
71 MEDIA_PIWG_FW_VOL_DP,
72 {
73 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
74 (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
75 }
76 },
77 { 0 }
78 },
79 {
80 END_DEVICE_PATH_TYPE,
81 END_ENTIRE_DEVICE_PATH_SUBTYPE,
82 {
83 END_DEVICE_PATH_LENGTH,
84 0
85 }
86 }
87 };
88
89 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
90 FVB_DEVICE_SIGNATURE,
91 NULL,
92 0,
93 {
94 FvbProtocolGetAttributes,
95 FvbProtocolSetAttributes,
UpdateMacAddress(VOID)96 FvbProtocolGetPhysicalAddress,
97 FvbProtocolGetBlockSize,
98 FvbProtocolRead,
99 FvbProtocolWrite,
100 FvbProtocolEraseBlocks,
101 NULL
102 }
103 };
104
105 /*++
106
107 Routine Description:
108 Retrieves the physical address of a memory mapped FV
109
110 Arguments:
111 Instance - The FV instance whose base address is going to be
112 returned
113 Global - Pointer to ESAL_FWB_GLOBAL that contains all
114 instance data
115 FwhInstance - The EFI_FW_VOL_INSTANCE fimrware instance structure
116
117 Returns:
118 EFI_SUCCESS - Successfully returns
119 EFI_INVALID_PARAMETER - Instance not found
120
121 --*/
122 EFI_STATUS
123 GetFvbInstance (
124 IN UINTN Instance,
125 IN ESAL_FWB_GLOBAL *Global,
126 OUT EFI_FW_VOL_INSTANCE **FwhInstance
127 )
128 {
129 EFI_FW_VOL_INSTANCE *FwhRecord;
130
131 *FwhInstance = NULL;
132 if (Instance >= Global->NumFv) {
133 return EFI_INVALID_PARAMETER;
134 }
135 //
136 // Find the right instance of the FVB private data
137 //
138 FwhRecord = Global->FvInstance;
139 while (Instance > 0) {
140 FwhRecord = (EFI_FW_VOL_INSTANCE *)
141 (
142 (UINTN)FwhRecord + FwhRecord->VolumeHeader.HeaderLength +
AddUsbCompatibleProperty(VOID)143 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
144 );
145 Instance--;
146 }
147
148 *FwhInstance = FwhRecord;
149
150 return EFI_SUCCESS;
151 }
152
153 /*++
154
155 Routine Description:
156 Retrieves the physical address of a memory mapped FV
157
158 Arguments:
159 Instance - The FV instance whose base address is going to be
160 returned
161 Address - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
162 that on successful return, contains the base
163 address of the firmware volume.
164 Global - Pointer to ESAL_FWB_GLOBAL that contains all
165 instance data
166
167 Returns:
168 EFI_SUCCESS - Successfully returns
169 EFI_INVALID_PARAMETER - Instance not found
170
171 --*/
172 EFI_STATUS
173 FvbGetPhysicalAddress (
174 IN UINTN Instance,
175 OUT EFI_PHYSICAL_ADDRESS *Address,
176 IN ESAL_FWB_GLOBAL *Global
177 )
178 {
179 EFI_FW_VOL_INSTANCE *FwhInstance;
180 EFI_STATUS Status;
181
182 //
183 // Find the right instance of the FVB private data
184 //
185 Status = GetFvbInstance (Instance, Global, &FwhInstance);
186 ASSERT_EFI_ERROR (Status);
187 *Address = FwhInstance->FvBase;
188
189 return EFI_SUCCESS;
190 }
191 /*++
192
193 Routine Description:
194 Retrieves attributes, insures positive polarity of attribute bits, returns
195 resulting attributes in output parameter
196
197 Arguments:
198 Instance - The FV instance whose attributes is going to be
199 returned
200 Attributes - Output buffer which contains attributes
201 Global - Pointer to ESAL_FWB_GLOBAL that contains all
202 instance data
203
204 Returns:
205 EFI_SUCCESS - Successfully returns
206 EFI_INVALID_PARAMETER - Instance not found
207
208 --*/
CleanMemoryNodes(VOID)209 EFI_STATUS
210 FvbGetVolumeAttributes (
211 IN UINTN Instance,
212 OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
213 IN ESAL_FWB_GLOBAL *Global
214 )
215 {
216 EFI_FW_VOL_INSTANCE *FwhInstance;
217 EFI_STATUS Status;
218
219 //
220 // Find the right instance of the FVB private data
221 //
222 Status = GetFvbInstance (Instance, Global, &FwhInstance);
223 ASSERT_EFI_ERROR (Status);
224 *Attributes = FwhInstance->VolumeHeader.Attributes;
225
226 return EFI_SUCCESS;
227 }
228
229 /*++
230
231 Routine Description:
232 Retrieves the starting address of an LBA in an FV
233
234 Arguments:
235 Instance - The FV instance which the Lba belongs to
236 Lba - The logical block address
SanitizePSCI(VOID)237 LbaAddress - On output, contains the physical starting address
238 of the Lba
239 LbaLength - On output, contains the length of the block
240 NumOfBlocks - A pointer to a caller allocated UINTN in which the
241 number of consecutive blocks starting with Lba is
242 returned. All blocks in this range have a size of
243 BlockSize
244 Global - Pointer to ESAL_FWB_GLOBAL that contains all
245 instance data
246
247 Returns:
248 EFI_SUCCESS - Successfully returns
249 EFI_INVALID_PARAMETER - Instance not found
250
251 --*/
252 EFI_STATUS
253 FvbGetLbaAddress (
254 IN UINTN Instance,
255 IN EFI_LBA Lba,
256 OUT UINTN *LbaAddress,
257 OUT UINTN *LbaLength,
258 OUT UINTN *NumOfBlocks,
259 IN ESAL_FWB_GLOBAL *Global
260 )
261 {
262 UINT32 NumBlocks;
263 UINT32 BlockLength;
264 UINTN Offset;
265 EFI_LBA StartLba;
266 EFI_LBA NextLba;
267 EFI_FW_VOL_INSTANCE *FwhInstance;
268 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
269 EFI_STATUS Status;
270
271 //
272 // Find the right instance of the FVB private data
273 //
274 Status = GetFvbInstance (Instance, Global, &FwhInstance);
275 ASSERT_EFI_ERROR (Status);
276
277 StartLba = 0;
278 Offset = 0;
279 BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
280
281 //
282 // Parse the blockmap of the FV to find which map entry the Lba belongs to
283 //
284 while (TRUE) {
285 NumBlocks = BlockMap->NumBlocks;
286 BlockLength = BlockMap->Length;
287
288 if (NumBlocks == 0 || BlockLength == 0) {
289 return EFI_INVALID_PARAMETER;
290 }
291
292 NextLba = StartLba + NumBlocks;
293
294 //
295 // The map entry found
296 //
297 if (Lba >= StartLba && Lba < NextLba) {
298 Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
299 if (LbaAddress != NULL) {
300 *LbaAddress = FwhInstance->FvBase + Offset;
301 }
302
303 if (LbaLength != NULL) {
304 *LbaLength = BlockLength;
305 }
306
307 if (NumOfBlocks != NULL) {
308 *NumOfBlocks = (UINTN) (NextLba - Lba);
309 }
310
311 return EFI_SUCCESS;
312 }
313
314 StartLba = NextLba;
315 Offset = Offset + NumBlocks * BlockLength;
316 BlockMap++;
317 }
318 }
319 /*++
320
321 Routine Description:
322 Modifies the current settings of the firmware volume according to the
323 input parameter, and returns the new setting of the volume
324
325 Arguments:
326 Instance - The FV instance whose attributes is going to be
327 modified
328 Attributes - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
329 containing the desired firmware volume settings.
330 On successful return, it contains the new settings
331 of the firmware volume
332 Global - Pointer to ESAL_FWB_GLOBAL that contains all
333 instance data
334
335 Returns:
336 EFI_SUCCESS - Successfully returns
337 EFI_ACCESS_DENIED - The volume setting is locked and cannot be modified
338 EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
339 in conflict with the capabilities as declared in
340 the firmware volume header
341
342 --*/
343 EFI_STATUS
344 FvbSetVolumeAttributes (
345 IN UINTN Instance,
346 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes,
347 IN ESAL_FWB_GLOBAL *Global
FdtDxeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)348 )
349 {
350 EFI_FW_VOL_INSTANCE *FwhInstance;
351 EFI_FVB_ATTRIBUTES_2 OldAttributes;
352 EFI_FVB_ATTRIBUTES_2 *AttribPtr;
353 UINT32 Capabilities;
354 UINT32 OldStatus;
355 UINT32 NewStatus;
356 EFI_STATUS Status;
357 EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;
358
359 //
360 // Find the right instance of the FVB private data
361 //
362 Status = GetFvbInstance (Instance, Global, &FwhInstance);
363 ASSERT_EFI_ERROR (Status);
364
365 AttribPtr =
366 (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
367 OldAttributes = *AttribPtr;
368 Capabilities = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
369 EFI_FVB2_READ_ENABLED_CAP | \
370 EFI_FVB2_WRITE_DISABLED_CAP | \
371 EFI_FVB2_WRITE_ENABLED_CAP | \
372 EFI_FVB2_LOCK_CAP \
373 );
374 OldStatus = OldAttributes & EFI_FVB2_STATUS;
375 NewStatus = *Attributes & EFI_FVB2_STATUS;
376
377 UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP | \
378 EFI_FVB2_READ_ENABLED_CAP | \
379 EFI_FVB2_WRITE_DISABLED_CAP | \
380 EFI_FVB2_WRITE_ENABLED_CAP | \
381 EFI_FVB2_LOCK_CAP | \
382 EFI_FVB2_STICKY_WRITE | \
383 EFI_FVB2_MEMORY_MAPPED | \
384 EFI_FVB2_ERASE_POLARITY | \
385 EFI_FVB2_READ_LOCK_CAP | \
386 EFI_FVB2_WRITE_LOCK_CAP | \
387 EFI_FVB2_ALIGNMENT;
388
389 //
390 // Some attributes of FV is read only can *not* be set
391 //
392 if ((OldAttributes & UnchangedAttributes) ^
393 (*Attributes & UnchangedAttributes)) {
394 return EFI_INVALID_PARAMETER;
395 }
396 //
397 // If firmware volume is locked, no status bit can be updated
398 //
399 if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
400 if (OldStatus ^ NewStatus) {
401 return EFI_ACCESS_DENIED;
402 }
403 }
404 //
405 // Test read disable
406 //
407 if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
408 if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
409 return EFI_INVALID_PARAMETER;
410 }
411 }
412 //
413 // Test read enable
414 //
415 if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
416 if (NewStatus & EFI_FVB2_READ_STATUS) {
417 return EFI_INVALID_PARAMETER;
418 }
419 }
420 //
421 // Test write disable
422 //
423 if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
424 if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
425 return EFI_INVALID_PARAMETER;
426 }
427 }
428 //
429 // Test write enable
430 //
431 if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
432 if (NewStatus & EFI_FVB2_WRITE_STATUS) {
433 return EFI_INVALID_PARAMETER;
434 }
435 }
436 //
437 // Test lock
438 //
439 if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
440 if (NewStatus & EFI_FVB2_LOCK_STATUS) {
441 return EFI_INVALID_PARAMETER;
442 }
443 }
444
445 *AttribPtr = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
446 *AttribPtr = (*AttribPtr) | NewStatus;
447 *Attributes = *AttribPtr;
448
449 return EFI_SUCCESS;
450 }
451 /*++
452
453 Routine Description:
454
455 Retrieves the physical address of the device.
456
457 Arguments:
458
459 This - Calling context
460 Address - Output buffer containing the address.
461
462 Returns:
463 EFI_SUCCESS - Successfully returns
464
465 --*/
466 EFI_STATUS
467 EFIAPI
468 FvbProtocolGetPhysicalAddress (
469 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
470 OUT EFI_PHYSICAL_ADDRESS *Address
471 )
472 {
473 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
474
475 FvbDevice = FVB_DEVICE_FROM_THIS (This);
476
477 return FvbGetPhysicalAddress (FvbDevice->Instance, Address,
478 mFvbModuleGlobal);
479 }
480
481 /*++
482
483 Routine Description:
484 Retrieve the size of a logical block
485
486 Arguments:
487 This - Calling context
488 Lba - Indicates which block to return the size for.
489 BlockSize - A pointer to a caller allocated UINTN in which
490 the size of the block is returned
491 NumOfBlocks - a pointer to a caller allocated UINTN in which the
492 number of consecutive blocks starting with Lba is
493 returned. All blocks in this range have a size of
494 BlockSize
495
496 Returns:
497 EFI_SUCCESS - The firmware volume was read successfully and
498 contents are in Buffer
499
500 --*/
501 EFI_STATUS
502 EFIAPI
503 FvbProtocolGetBlockSize (
504 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
505 IN CONST EFI_LBA Lba,
506 OUT UINTN *BlockSize,
507 OUT UINTN *NumOfBlocks
508 )
509 {
510 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
511
512 FvbDevice = FVB_DEVICE_FROM_THIS (This);
513
514 return FvbGetLbaAddress (
515 FvbDevice->Instance,
516 Lba,
517 NULL,
518 BlockSize,
519 NumOfBlocks,
520 mFvbModuleGlobal
521 );
522 }
523
524 /*++
525
526 Routine Description:
527 Retrieves Volume attributes. No polarity translations are done.
528
529 Arguments:
530 This - Calling context
531 Attributes - output buffer which contains attributes
532
533 Returns:
534 EFI_SUCCESS - Successfully returns
535
536 --*/
537 EFI_STATUS
538 EFIAPI
539 FvbProtocolGetAttributes (
540 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
541 OUT EFI_FVB_ATTRIBUTES_2 *Attributes
542 )
543 {
544 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
545
546 FvbDevice = FVB_DEVICE_FROM_THIS (This);
547
548 return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes,
549 mFvbModuleGlobal);
550 }
551
552 /*++
553
554 Routine Description:
555 Sets Volume attributes. No polarity translations are done.
556
557 Arguments:
558 This - Calling context
559 Attributes - output buffer which contains attributes
560
561 Returns:
562 EFI_SUCCESS - Successfully returns
563
564 --*/
565 EFI_STATUS
566 EFIAPI
567 FvbProtocolSetAttributes (
568 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
569 IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
570 )
571 {
572 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
573
574 FvbDevice = FVB_DEVICE_FROM_THIS (This);
575
576 return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes,
577 mFvbModuleGlobal);
578 }
579
580 /*++
581
582 Routine Description:
583
584 The EraseBlock() function erases one or more blocks as denoted by the
585 variable argument list. The entire parameter list of blocks must be
586 verified prior to erasing any blocks. If a block is requested that does
587 not exist within the associated firmware volume (it has a larger index than
588 the last block of the firmware volume), the EraseBlock() function must
589 return EFI_INVALID_PARAMETER without modifying the contents of the firmware
590 volume.
591
592 Arguments:
593 This - Calling context
594 ... - Starting LBA followed by Number of Lba to erase.
595 a -1 to terminate the list.
596
597 Returns:
598 EFI_SUCCESS - The erase request was successfully completed
599 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
600 EFI_DEVICE_ERROR - The block device is not functioning correctly and
601 could not be written. Firmware device may have been
602 partially erased
603
604 --*/
605 EFI_STATUS
606 EFIAPI
607 FvbProtocolEraseBlocks (
608 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
609 ...
610 )
611 {
612 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
613 EFI_FW_VOL_INSTANCE *FwhInstance;
614 UINTN NumOfBlocks;
615 VA_LIST args;
616 EFI_LBA StartingLba;
617 UINTN NumOfLba;
618 EFI_STATUS Status;
619
620 FvbDevice = FVB_DEVICE_FROM_THIS (This);
621
622 Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal,
623 &FwhInstance);
624 ASSERT_EFI_ERROR (Status);
625
626 NumOfBlocks = FwhInstance->NumOfBlocks;
627
628 VA_START (args, This);
629
630 do {
631 StartingLba = VA_ARG (args, EFI_LBA);
632 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
633 break;
634 }
635
636 NumOfLba = VA_ARG (args, UINT32);
637
638 //
639 // Check input parameters
640 //
641 if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
642 VA_END (args);
643 return EFI_INVALID_PARAMETER;
644 }
645 } while (1);
646
647 VA_END (args);
648
649 VA_START (args, This);
650 do {
651 StartingLba = VA_ARG (args, EFI_LBA);
652 if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
653 break;
654 }
655
656 NumOfLba = VA_ARG (args, UINT32);
657
658 while (NumOfLba > 0) {
659 Status = RamFlashEraseBlock (StartingLba);
660 if (EFI_ERROR (Status)) {
661 VA_END (args);
662 return Status;
663 }
664
665 StartingLba++;
666 NumOfLba--;
667 }
668
669 } while (1);
670
671 VA_END (args);
672
673 return EFI_SUCCESS;
674 }
675
676 /*++
677
678 Routine Description:
679
680 Writes data beginning at Lba:Offset from FV. The write terminates either
681 when *NumBytes of data have been written, or when a block boundary is
682 reached. *NumBytes is updated to reflect the actual number of bytes
683 written. The write opertion does not include erase. This routine will
684 attempt to write only the specified bytes. If the writes do not stick,
685 it will return an error.
686
687 Arguments:
688 This - Calling context
689 Lba - Block in which to begin write
690 Offset - Offset in the block at which to begin write
691 NumBytes - On input, indicates the requested write size. On
692 output, indicates the actual number of bytes
693 written
694 Buffer - Buffer containing source data for the write.
695
696 Returns:
697 EFI_SUCCESS - The firmware volume was written successfully
698 EFI_BAD_BUFFER_SIZE - Write attempted across a LBA boundary. On output,
699 NumBytes contains the total number of bytes
700 actually written
701 EFI_ACCESS_DENIED - The firmware volume is in the WriteDisabled state
702 EFI_DEVICE_ERROR - The block device is not functioning correctly and
703 could not be written
704 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
705
706 --*/
707 EFI_STATUS
708 EFIAPI
709 FvbProtocolWrite (
710 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
711 IN EFI_LBA Lba,
712 IN UINTN Offset,
713 IN OUT UINTN *NumBytes,
714 IN UINT8 *Buffer
715 )
716 {
717 return RamFlashWrite (Lba, Offset, NumBytes, Buffer);
718 }
719
720 /*++
721
722 Routine Description:
723
724 Reads data beginning at Lba:Offset from FV. The Read terminates either
725 when *NumBytes of data have been read, or when a block boundary is
726 reached. *NumBytes is updated to reflect the actual number of bytes
727 written. The write opertion does not include erase. This routine will
728 attempt to write only the specified bytes. If the writes do not stick,
729 it will return an error.
730
731 Arguments:
732 This - Calling context
733 Lba - Block in which to begin Read
734 Offset - Offset in the block at which to begin Read
735 NumBytes - On input, indicates the requested write size. On
736 output, indicates the actual number of bytes Read
737 Buffer - Buffer containing source data for the Read.
738
739 Returns:
740 EFI_SUCCESS - The firmware volume was read successfully and
741 contents are in Buffer
742 EFI_BAD_BUFFER_SIZE - Read attempted across a LBA boundary. On output,
743 NumBytes contains the total number of bytes
744 returned in Buffer
745 EFI_ACCESS_DENIED - The firmware volume is in the ReadDisabled state
746 EFI_DEVICE_ERROR - The block device is not functioning correctly and
747 could not be read
748 EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
749
750 --*/
751 EFI_STATUS
752 EFIAPI
753 FvbProtocolRead (
754 IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,
755 IN CONST EFI_LBA Lba,
756 IN CONST UINTN Offset,
757 IN OUT UINTN *NumBytes,
758 IN UINT8 *Buffer
759 )
760 {
761 return RamFlashRead (Lba, Offset, NumBytes, Buffer);
762 }
763
764 /*++
765
766 Routine Description:
767 Check the integrity of firmware volume header
768
769 Arguments:
770 FwVolHeader - A pointer to a firmware volume header
771
772 Returns:
773 EFI_SUCCESS - The firmware volume is consistent
774 EFI_NOT_FOUND - The firmware volume has corrupted. So it is not an
775 FV
776
777 --*/
778 EFI_STATUS
779 ValidateFvHeader (
780 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader
781 )
782 {
783 UINT16 Checksum;
784
785 //
786 // Verify the header revision, header signature, length
787 // Length of FvBlock cannot be 2**64-1
788 // HeaderLength cannot be an odd number
789 //
790 if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
791 (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
792 (FwVolHeader->FvLength == ((UINTN) -1)) ||
793 ((FwVolHeader->HeaderLength & 0x01) != 0)
794 ) {
795 return EFI_NOT_FOUND;
796 }
797
798 //
799 // Verify the header checksum
800 //
801
802 Checksum = CalculateSum16 ((UINT16 *) FwVolHeader,
803 FwVolHeader->HeaderLength);
804 if (Checksum != 0) {
805 UINT16 Expected;
806
807 Expected =
808 (UINT16) (((UINTN) FwVolHeader->Checksum + 0x10000 - Checksum) & 0xffff);
809
810 DEBUG ((DEBUG_INFO, "FV@%p Checksum is 0x%x, expected 0x%x\n",
811 FwVolHeader, FwVolHeader->Checksum, Expected));
812 return EFI_NOT_FOUND;
813 }
814
815 return EFI_SUCCESS;
816 }
817
818 STATIC
819 EFI_STATUS
820 MarkMemoryRangeForRuntimeAccess (
821 EFI_PHYSICAL_ADDRESS BaseAddress,
822 UINTN Length
823 )
824 {
825 EFI_STATUS Status;
826
827 //
828 // Mark flash region as runtime memory
829 //
830 Status = gDS->RemoveMemorySpace (
831 BaseAddress,
832 Length
833 );
834
835 Status = gDS->AddMemorySpace (
836 EfiGcdMemoryTypeSystemMemory,
837 BaseAddress,
838 Length,
839 EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
840 );
841 ASSERT_EFI_ERROR (Status);
842
843 Status = gBS->AllocatePages (
844 AllocateAddress,
845 EfiRuntimeServicesData,
846 EFI_SIZE_TO_PAGES (Length),
847 &BaseAddress
848 );
849 ASSERT_EFI_ERROR (Status);
850
851 return Status;
852 }
853
854 STATIC
855 EFI_STATUS
856 InitializeVariableFvHeader (
857 VOID
858 )
859 {
860 EFI_STATUS Status;
861 EFI_FIRMWARE_VOLUME_HEADER *GoodFwVolHeader;
862 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
863 UINTN Length;
864 UINTN WriteLength;
865 UINTN BlockSize;
866
867 FwVolHeader =
868 (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)
869 PcdGet32 (PcdPlatformFlashNvStorageVariableBase);
870
871 Length =
872 (FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
873 FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
874 FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize));
875
876 BlockSize = PcdGet32 (PcdVariableFdBlockSize);
877
878 Status = ValidateFvHeader (FwVolHeader);
879 if (!EFI_ERROR (Status)) {
880 DEBUG ((DEBUG_INFO, "ValidateFvHeader() return ok\n"));
881 if (FwVolHeader->FvLength != Length ||
882 FwVolHeader->BlockMap[0].Length != BlockSize) {
883 Status = EFI_VOLUME_CORRUPTED;
884 DEBUG ((DEBUG_INFO, "FwVolHeader->FvLength(%x) != Length(%x) || FwVolHeader->BlockMap[0].Length(%x) != BlockSize(%x)\n", FwVolHeader->FvLength, Length, FwVolHeader->BlockMap[0].Length, BlockSize));
885 }
886 }
887 else {
888 DEBUG ((DEBUG_INFO, "ValidateFvHeader() return failed\n"));
889 }
890 if (EFI_ERROR (Status)) {
891 UINTN Offset;
892 UINTN Start;
893
894 DEBUG ((DEBUG_INFO,
895 "Variable FV header is not valid. It will be reinitialized.\n"));
896
897 //
898 // Get FvbInfo to provide in FwhInstance.
899 //
900 Status = GetFvbInfo (Length, &GoodFwVolHeader);
901 ASSERT (!EFI_ERROR (Status));
902
903 Start = (UINTN)(UINT8*) FwVolHeader - PcdGet32 (PcdVariableFdBaseAddress);
904 ASSERT (Start % BlockSize == 0 && Length % BlockSize == 0);
905 ASSERT (GoodFwVolHeader->HeaderLength <= BlockSize);
906
907 //
908 // Erase all the blocks
909 //
910 for (Offset = Start; Offset < Start + Length; Offset += BlockSize) {
911 Status = RamFlashEraseBlock (Offset / BlockSize);
912 ASSERT_EFI_ERROR (Status);
913 }
914
915 //
916 // Write good FV header
917 //
918 WriteLength = GoodFwVolHeader->HeaderLength;
919 Status = RamFlashWrite (
920 Start / BlockSize,
921 0,
922 &WriteLength,
923 (UINT8 *) GoodFwVolHeader);
924 ASSERT_EFI_ERROR (Status);
925 ASSERT (WriteLength == GoodFwVolHeader->HeaderLength);
926 }
927
928 return Status;
929 }
930
931 /*++
932
933 Routine Description:
934 This function does common initialization for FVB services
935
936 Arguments:
937
938 Returns:
939
940 --*/
941 EFI_STATUS
942 EFIAPI
943 FvbInitialize (
944 IN EFI_HANDLE ImageHandle,
945 IN EFI_SYSTEM_TABLE *SystemTable
946 )
947 {
948 EFI_STATUS Status;
949 EFI_FW_VOL_INSTANCE *FwhInstance;
950 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
951 UINT32 BufferSize;
952 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
953 EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
954 UINT32 MaxLbaSize;
955 EFI_PHYSICAL_ADDRESS BaseAddress;
956 UINTN Length;
957 UINTN NumOfBlocks;
958
959 if (EFI_ERROR (RamFlashInitialize ())) {
960 //
961 // Return an error so image will be unloaded
962 //
963 DEBUG ((DEBUG_INFO,
964 "RAM flash was not detected. Writable FVB is not being installed.\n"));
965 return EFI_WRITE_PROTECTED;
966 }
967
968 //
969 // Allocate runtime services data for global variable, which contains
970 // the private data of all firmware volume block instances
971 //
972 mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
973 ASSERT (mFvbModuleGlobal != NULL);
974
975 BaseAddress = (UINTN) PcdGet32 (PcdVariableFdBaseAddress);
976 Length = PcdGet32 (PcdVariableFdSize);
977 DEBUG ((DEBUG_INFO, "FvbInitialize(): BaseAddress: 0x%lx Length:0x%x\n", BaseAddress, Length));
978 Status = InitializeVariableFvHeader ();
979 if (EFI_ERROR (Status)) {
980 DEBUG ((DEBUG_INFO,
981 "RAM Flash: Unable to initialize variable FV header\n"));
982 return EFI_WRITE_PROTECTED;
983 }
984
985 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;
986 Status = ValidateFvHeader (FwVolHeader);
987 if (EFI_ERROR (Status)) {
988 //
989 // Get FvbInfo
990 //
991 DEBUG ((DEBUG_INFO, "FvbInitialize(): ValidateFvHeader() return error(%r)\n", Status));
992
993 Status = GetFvbInfo (Length, &FwVolHeader);
994 if (EFI_ERROR (Status)) {
995 DEBUG ((DEBUG_INFO, "FvbInitialize(): GetFvbInfo (Length, &FwVolHeader) return error(%r)\n", Status));
996 return EFI_WRITE_PROTECTED;
997 }
998 }
999
1000 BufferSize = (sizeof (EFI_FW_VOL_INSTANCE) +
1001 FwVolHeader->HeaderLength -
1002 sizeof (EFI_FIRMWARE_VOLUME_HEADER)
1003 );
1004 mFvbModuleGlobal->FvInstance = AllocateRuntimePool (BufferSize);
1005 ASSERT (mFvbModuleGlobal->FvInstance != NULL);
1006
1007 FwhInstance = mFvbModuleGlobal->FvInstance;
1008
1009 mFvbModuleGlobal->NumFv = 0;
1010 MaxLbaSize = 0;
1011
1012 FwVolHeader =
1013 (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN)
1014 PcdGet32 (PcdPlatformFlashNvStorageVariableBase);
1015
1016 FwhInstance->FvBase = (UINTN) BaseAddress;
1017
1018 CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader,
1019 FwVolHeader->HeaderLength);
1020 FwVolHeader = &(FwhInstance->VolumeHeader);
1021
1022 NumOfBlocks = 0;
1023
1024 for (PtrBlockMapEntry = FwVolHeader->BlockMap;
1025 PtrBlockMapEntry->NumBlocks != 0;
1026 PtrBlockMapEntry++) {
1027 //
1028 // Get the maximum size of a block.
1029 //
1030 if (MaxLbaSize < PtrBlockMapEntry->Length) {
1031 MaxLbaSize = PtrBlockMapEntry->Length;
1032 }
1033
1034 NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1035 }
1036
1037 //
1038 // The total number of blocks in the FV.
1039 //
1040 FwhInstance->NumOfBlocks = NumOfBlocks;
1041
1042 //
1043 // Add a FVB Protocol Instance
1044 //
1045 FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1046 ASSERT (FvbDevice != NULL);
1047
1048 CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1049
1050 FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1051 mFvbModuleGlobal->NumFv++;
1052
1053 //
1054 // Set up the devicepath
1055 //
1056 if (FwVolHeader->ExtHeaderOffset == 0) {
1057 FV_MEMMAP_DEVICE_PATH *FvMemmapDevicePath;
1058
1059 //
1060 // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1061 //
1062 FvMemmapDevicePath = AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH),
1063 &mFvMemmapDevicePathTemplate);
1064 FvMemmapDevicePath->MemMapDevPath.StartingAddress = BaseAddress;
1065 FvMemmapDevicePath->MemMapDevPath.EndingAddress =
1066 BaseAddress + FwVolHeader->FvLength - 1;
1067 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvMemmapDevicePath;
1068 } else {
1069 FV_PIWG_DEVICE_PATH *FvPiwgDevicePath;
1070
1071 FvPiwgDevicePath = AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH),
1072 &mFvPIWGDevicePathTemplate);
1073 CopyGuid (
1074 &FvPiwgDevicePath->FvDevPath.FvName,
1075 (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
1076 );
1077 FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)FvPiwgDevicePath;
1078 }
1079
1080 //
1081 // Module type specific hook.
1082 //
1083 InstallProtocolInterfaces (FvbDevice);
1084
1085 MarkMemoryRangeForRuntimeAccess (BaseAddress, Length);
1086
1087 //
1088 // Set several PCD values to point to flash
1089 //
1090 Status = PcdSet64S (
1091 PcdFlashNvStorageVariableBase64,
1092 (UINTN) PcdGet32 (PcdPlatformFlashNvStorageVariableBase)
1093 );
1094 ASSERT_EFI_ERROR (Status);
1095 Status = PcdSet32S (
1096 PcdFlashNvStorageFtwWorkingBase,
1097 PcdGet32 (PcdPlatformFlashNvStorageFtwWorkingBase)
1098 );
1099 ASSERT_EFI_ERROR (Status);
1100 Status = PcdSet32S (
1101 PcdFlashNvStorageFtwSpareBase,
1102 PcdGet32 (PcdPlatformFlashNvStorageFtwSpareBase)
1103 );
1104 ASSERT_EFI_ERROR (Status);
1105
1106 FwhInstance = (EFI_FW_VOL_INSTANCE *)
1107 (
1108 (UINTN) FwhInstance + FwVolHeader->HeaderLength +
1109 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1110 );
1111
1112 //
1113 // Module type specific hook.
1114 //
1115 InstallVirtualAddressChangeHandler ();
1116 return EFI_SUCCESS;
1117 }
1118