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