1 /**@file
2 Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials
4 are licensed and made available under the terms and conditions of the BSD License
5 which accompanies this distribution.  The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php
7 
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10 
11 Module Name:
12 
13   FWBlockService.c
14 
15 Abstract:
16 
17 Revision History
18 
19 **/
20 #include "FWBlockService.h"
21 #include "EfiFlashMap.h"
22 #include "FileIo.h"
23 #include "FlashLayout.h"
24 
25 ESAL_FWB_GLOBAL       *mFvbModuleGlobal;
26 VOID                  *mSFSRegistration;
27 #define TRY_ASSIGN(var, value)  if(var != NULL) {*var = value;}
28 
29 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
30   FVB_DEVICE_SIGNATURE,
31   {
32     {
33       {
34         HARDWARE_DEVICE_PATH,
35         HW_MEMMAP_DP,
36         {
37           sizeof (MEMMAP_DEVICE_PATH),
38           0
39         }
40       },
41       EfiMemoryMappedIO,
42       0,
43       0,
44     },
45     {
46       END_DEVICE_PATH_TYPE,
47       END_ENTIRE_DEVICE_PATH_SUBTYPE,
48       {
49         sizeof (EFI_DEVICE_PATH_PROTOCOL),
50         0
51       }
52     }
53   },
54   0,
55   {
56     FvbProtocolGetAttributes,
57     FvbProtocolSetAttributes,
58     FvbProtocolGetPhysicalAddress,
59     FvbProtocolGetBlockSize,
60     FvbProtocolRead,
61     FvbProtocolWrite,
62     FvbProtocolEraseBlocks,
63     NULL
64   }
65 };
66 
67 
68 EFI_STATUS
FlashFdWrite(IN UINTN Address,IN EFI_FW_VOL_INSTANCE * FwhInstance,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)69 FlashFdWrite (
70   IN     UINTN                            Address,
71   IN     EFI_FW_VOL_INSTANCE              *FwhInstance,
72   IN OUT UINTN                            *NumBytes,
73   IN     UINT8                            *Buffer
74   )
75 /*++
76 
77 Routine Description:
78   Writes specified number of bytes from the input buffer to the address
79 
80 Arguments:
81 
82 Returns:
83 
84 --*/
85 {
86   EFI_STATUS          Status;
87   EFI_FILE_PROTOCOL   *File;
88   UINTN               FileOffset;
89   UINTN               BufferForFile;
90   UINTN               Length;
91 
92   Status = EFI_SUCCESS;
93   CopyMem ((VOID *) Address, Buffer, *NumBytes);
94 
95   if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
96     Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
97     ASSERT_EFI_ERROR (Status);
98     if (!EFI_ERROR (Status)) {
99       if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
100         FileOffset = 0;
101         BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
102         Length = *NumBytes - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
103       } else {
104         FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
105         BufferForFile = Address;
106         Length = *NumBytes;
107       }
108 
109       Status = FileWrite (File, FileOffset, BufferForFile, Length);
110       ASSERT_EFI_ERROR (Status);
111       FileClose (File);
112     }
113   }
114   return Status;
115 }
116 
117 EFI_STATUS
FlashFdErase(IN UINTN Address,IN EFI_FW_VOL_INSTANCE * FwhInstance,IN UINTN LbaLength)118 FlashFdErase (
119   IN UINTN                                Address,
120   IN EFI_FW_VOL_INSTANCE                  *FwhInstance,
121   IN UINTN                                LbaLength
122   )
123 /*++
124 
125 Routine Description:
126   Erase a certain block from address LbaWriteAddress
127 
128 Arguments:
129 
130 Returns:
131 
132 --*/
133 {
134   EFI_STATUS           Status;
135   EFI_FILE_PROTOCOL    *File;
136   UINTN                FileOffset;
137   UINTN                BufferForFile;
138   UINTN                Length;
139 
140   Status = EFI_SUCCESS;
141 
142   SetMem ((VOID *)Address, LbaLength, 0xff);
143 
144   if (!EfiAtRuntime () && (FwhInstance->Device != NULL)) {
145     Status = FileOpen (FwhInstance->Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE);
146     ASSERT_EFI_ERROR (Status);
147     if (!EFI_ERROR (Status)) {
148       if (Address - FwhInstance->FvBase[FVB_PHYSICAL] < FwhInstance->Offset) {
149         FileOffset = 0;
150         BufferForFile = FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset;
151         Length = LbaLength - (FwhInstance->Offset - (Address - FwhInstance->FvBase[FVB_PHYSICAL]));
152       } else {
153         FileOffset = Address - FwhInstance->FvBase[FVB_PHYSICAL] - FwhInstance->Offset;
154         BufferForFile = Address;
155         Length = LbaLength;
156       }
157 
158       Status = FileWrite (File, FileOffset, BufferForFile, Length);
159       ASSERT_EFI_ERROR (Status);
160       FileClose (File);
161     }
162   }
163   return Status;
164 }
165 
166 VOID
167 EFIAPI
FvbVirtualddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)168 FvbVirtualddressChangeEvent (
169   IN EFI_EVENT        Event,
170   IN VOID             *Context
171   )
172 /*++
173 
174 Routine Description:
175 
176   Fixup internal data so that EFI and SAL can be call in virtual mode.
177   Call the passed in Child Notify event and convert the mFvbModuleGlobal
178   date items to there virtual address.
179 
180   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
181   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
182                                                 instance data.
183 
184 Arguments:
185 
186   (Standard EFI notify event - EFI_EVENT_NOTIFY)
187 
188 Returns:
189 
190   None
191 
192 --*/
193 {
194   EFI_FW_VOL_INSTANCE *FwhInstance;
195   UINTN               Index;
196 
197   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
198 
199   //
200   // Convert the base address of all the instances
201   //
202   Index       = 0;
203   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
204   while (Index < mFvbModuleGlobal->NumFv) {
205     EfiConvertPointer (0, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
206     FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwhInstance->VolumeHeader.HeaderLength
207                     + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
208     Index++;
209   }
210 
211   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
212   EfiConvertPointer (0, (VOID **) &mFvbModuleGlobal);
213 }
214 
215 EFI_STATUS
GetFvbInstance(IN UINTN Instance,IN ESAL_FWB_GLOBAL * Global,OUT EFI_FW_VOL_INSTANCE ** FwhInstance,IN BOOLEAN Virtual)216 GetFvbInstance (
217   IN  UINTN                               Instance,
218   IN  ESAL_FWB_GLOBAL                     *Global,
219   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
220   IN BOOLEAN                              Virtual
221   )
222 /*++
223 
224 Routine Description:
225   Retrieves the physical address of a memory mapped FV
226 
227 Arguments:
228   Instance              - The FV instance whose base address is going to be
229                           returned
230   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
231                           instance data
232   FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
233   Virtual               - Whether CPU is in virtual or physical mode
234 
235 Returns:
236   EFI_SUCCESS           - Successfully returns
237   EFI_INVALID_PARAMETER - Instance not found
238 
239 --*/
240 {
241   EFI_FW_VOL_INSTANCE *FwhRecord;
242 
243   if (Instance >= Global->NumFv) {
244     return EFI_INVALID_PARAMETER;
245   }
246   //
247   // Find the right instance of the FVB private data
248   //
249   FwhRecord = Global->FvInstance[Virtual];
250   while (Instance > 0) {
251     FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength
252                      + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));
253     Instance--;
254   }
255 
256   *FwhInstance = FwhRecord;
257 
258   return EFI_SUCCESS;
259 }
260 
261 EFI_STATUS
FvbGetPhysicalAddress(IN UINTN Instance,OUT EFI_PHYSICAL_ADDRESS * Address,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)262 FvbGetPhysicalAddress (
263   IN UINTN                                Instance,
264   OUT EFI_PHYSICAL_ADDRESS                *Address,
265   IN ESAL_FWB_GLOBAL                      *Global,
266   IN BOOLEAN                              Virtual
267   )
268 /*++
269 
270 Routine Description:
271   Retrieves the physical address of a memory mapped FV
272 
273 Arguments:
274   Instance              - The FV instance whose base address is going to be
275                           returned
276   Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
277                           that on successful return, contains the base address
278                           of the firmware volume.
279   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
280                           instance data
281   Virtual               - Whether CPU is in virtual or physical mode
282 
283 Returns:
284   EFI_SUCCESS           - Successfully returns
285   EFI_INVALID_PARAMETER - Instance not found
286 
287 --*/
288 {
289   EFI_FW_VOL_INSTANCE *FwhInstance;
290   EFI_STATUS          Status;
291 
292   //
293   // Find the right instance of the FVB private data
294   //
295   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
296   ASSERT_EFI_ERROR (Status);
297   *Address = FwhInstance->FvBase[Virtual];
298 
299   return EFI_SUCCESS;
300 }
301 
302 EFI_STATUS
FvbGetVolumeAttributes(IN UINTN Instance,OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)303 FvbGetVolumeAttributes (
304   IN UINTN                                Instance,
305   OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
306   IN ESAL_FWB_GLOBAL                      *Global,
307   IN BOOLEAN                              Virtual
308   )
309 /*++
310 
311 Routine Description:
312   Retrieves attributes, insures positive polarity of attribute bits, returns
313   resulting attributes in output parameter
314 
315 Arguments:
316   Instance              - The FV instance whose attributes is going to be
317                           returned
318   Attributes            - Output buffer which contains attributes
319   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
320                           instance data
321   Virtual               - Whether CPU is in virtual or physical mode
322 
323 Returns:
324   EFI_SUCCESS           - Successfully returns
325   EFI_INVALID_PARAMETER - Instance not found
326 
327 --*/
328 {
329   EFI_FW_VOL_INSTANCE *FwhInstance;
330   EFI_STATUS          Status;
331 
332   //
333   // Find the right instance of the FVB private data
334   //
335   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
336   ASSERT_EFI_ERROR (Status);
337   *Attributes = FwhInstance->VolumeHeader.Attributes;
338 
339   return EFI_SUCCESS;
340 }
341 
342 EFI_STATUS
FvbGetLbaAddress(IN UINTN Instance,IN EFI_LBA Lba,OUT UINTN * LbaAddress OPTIONAL,OUT UINTN * LbaLength OPTIONAL,OUT UINTN * NumOfBlocks OPTIONAL,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)343 FvbGetLbaAddress (
344   IN  UINTN                               Instance,
345   IN  EFI_LBA                             Lba,
346   OUT UINTN                               *LbaAddress  OPTIONAL,
347   OUT UINTN                               *LbaLength   OPTIONAL,
348   OUT UINTN                               *NumOfBlocks OPTIONAL,
349   IN  ESAL_FWB_GLOBAL                     *Global,
350   IN  BOOLEAN                             Virtual
351   )
352 /*++
353 
354 Routine Description:
355   Retrieves the starting address of an LBA in an FV
356 
357 Arguments:
358   Instance              - The FV instance which the Lba belongs to
359   Lba                   - The logical block address
360   LbaAddress            - On output, contains the physical starting address
361                           of the Lba for writing
362   LbaLength             - On output, contains the length of the block
363   NumOfBlocks           - A pointer to a caller allocated UINTN in which the
364                           number of consecutive blocks starting with Lba is
365                           returned. All blocks in this range have a size of
366                           BlockSize
367   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
368                           instance data
369   Virtual               - Whether CPU is in virtual or physical mode
370 
371 Returns:
372   EFI_SUCCESS           - Successfully returns
373   EFI_INVALID_PARAMETER - Instance not found
374 
375 --*/
376 {
377   UINT32                  NumBlocks;
378   UINT32                  BlockLength;
379   UINTN                   Offset;
380   EFI_LBA                 StartLba;
381   EFI_LBA                 NextLba;
382   EFI_FW_VOL_INSTANCE     *FwhInstance;
383   EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
384   EFI_STATUS              Status;
385 
386   //
387   // Find the right instance of the FVB private data
388   //
389   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
390   ASSERT_EFI_ERROR (Status);
391 
392   StartLba  = 0;
393   Offset    = 0;
394   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
395 
396   //
397   // Parse the blockmap of the FV to find which map entry the Lba belongs to
398   //
399   while (TRUE) {
400     NumBlocks   = BlockMap->NumBlocks;
401     BlockLength = BlockMap->Length;
402 
403     if (NumBlocks == 0 || BlockLength == 0) {
404       return EFI_INVALID_PARAMETER;
405     }
406 
407     NextLba = StartLba + NumBlocks;
408 
409     //
410     // The map entry found
411     //
412     if (Lba >= StartLba && Lba < NextLba) {
413       Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
414 
415       if (LbaAddress) {
416         *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
417       }
418 
419       if (LbaLength) {
420         *LbaLength = BlockLength;
421       }
422 
423       if (NumOfBlocks) {
424         *NumOfBlocks = (UINTN) (NextLba - Lba);
425       }
426 
427       return EFI_SUCCESS;
428     }
429 
430     StartLba  = NextLba;
431     Offset    = Offset + NumBlocks * BlockLength;
432     BlockMap++;
433   }
434 }
435 
436 EFI_STATUS
FvbReadBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)437 FvbReadBlock (
438   IN UINTN                                Instance,
439   IN EFI_LBA                              Lba,
440   IN UINTN                                BlockOffset,
441   IN OUT UINTN                            *NumBytes,
442   IN UINT8                                *Buffer,
443   IN ESAL_FWB_GLOBAL                      *Global,
444   IN BOOLEAN                              Virtual
445   )
446 /*++
447 
448 Routine Description:
449   Reads specified number of bytes into a buffer from the specified block
450 
451 Arguments:
452   Instance              - The FV instance to be read from
453   Lba                   - The logical block address to be read from
454   BlockOffset           - Offset into the block at which to begin reading
455   NumBytes              - Pointer that on input contains the total size of
456                           the buffer. On output, it contains the total number
457                           of bytes read
458   Buffer                - Pointer to a caller allocated buffer that will be
459                           used to hold the data read
460   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
461                           instance data
462   Virtual               - Whether CPU is in virtual or physical mode
463 
464 Returns:
465   EFI_SUCCESS           - The firmware volume was read successfully and
466                           contents are in Buffer
467   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
468                           NumBytes contains the total number of bytes returned
469                           in Buffer
470   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
471   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
472                           could not be read
473   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
474 
475 --*/
476 {
477   EFI_FVB_ATTRIBUTES_2  Attributes;
478   UINTN                 LbaAddress;
479   UINTN                 LbaLength;
480   EFI_STATUS            Status;
481 
482   //
483   // Check for invalid conditions
484   //
485   if ((NumBytes == NULL) || (Buffer == NULL)) {
486     return EFI_INVALID_PARAMETER;
487   }
488 
489   if (*NumBytes == 0) {
490     return EFI_INVALID_PARAMETER;
491   }
492 
493   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
494   if (EFI_ERROR (Status)) {
495     return Status;
496   }
497   //
498   // Check if the FV is read enabled
499   //
500   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
501 
502   if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
503     return EFI_ACCESS_DENIED;
504   }
505   //
506   // Perform boundary checks and adjust NumBytes
507   //
508   if (BlockOffset > LbaLength) {
509     return EFI_INVALID_PARAMETER;
510   }
511 
512   if (LbaLength < (*NumBytes + BlockOffset)) {
513     *NumBytes = (UINT32) (LbaLength - BlockOffset);
514     Status    = EFI_BAD_BUFFER_SIZE;
515   }
516 
517   CopyMem (Buffer, (VOID *) (LbaAddress + BlockOffset), (UINTN) *NumBytes);
518 
519   return Status;
520 }
521 EFI_STATUS
FvbWriteBlock(IN UINTN Instance,IN EFI_LBA Lba,IN UINTN BlockOffset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)522 FvbWriteBlock (
523   IN UINTN                                Instance,
524   IN EFI_LBA                              Lba,
525   IN UINTN                                BlockOffset,
526   IN OUT UINTN                            *NumBytes,
527   IN UINT8                                *Buffer,
528   IN ESAL_FWB_GLOBAL                      *Global,
529   IN BOOLEAN                              Virtual
530   )
531 /*++
532 
533 Routine Description:
534   Writes specified number of bytes from the input buffer to the block
535 
536 Arguments:
537   Instance              - The FV instance to be written to
538   Lba                   - The starting logical block index to write to
539   BlockOffset           - Offset into the block at which to begin writing
540   NumBytes              - Pointer that on input contains the total size of
541                           the buffer. On output, it contains the total number
542                           of bytes actually written
543   Buffer                - Pointer to a caller allocated buffer that contains
544                           the source for the write
545   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
546                           instance data
547   Virtual               - Whether CPU is in virtual or physical mode
548 
549 Returns:
550   EFI_SUCCESS           - The firmware volume was written successfully
551   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
552                           NumBytes contains the total number of bytes
553                           actually written
554   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
555   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
556                           could not be written
557   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
558 
559 --*/
560 {
561   EFI_FVB_ATTRIBUTES_2  Attributes;
562   UINTN                 LbaAddress;
563   UINTN                 LbaLength;
564   EFI_FW_VOL_INSTANCE   *FwhInstance;
565   EFI_STATUS            Status;
566   EFI_STATUS            ReturnStatus;
567 
568   //
569   // Find the right instance of the FVB private data
570   //
571   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
572   ASSERT_EFI_ERROR (Status);
573 
574   //
575   // Writes are enabled in the init routine itself
576   //
577   if (!FwhInstance->WriteEnabled) {
578     return EFI_ACCESS_DENIED;
579   }
580   //
581   // Check for invalid conditions
582   //
583   if ((NumBytes == NULL) || (Buffer == NULL)) {
584     return EFI_INVALID_PARAMETER;
585   }
586 
587   if (*NumBytes == 0) {
588     return EFI_INVALID_PARAMETER;
589   }
590 
591   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
592   if (EFI_ERROR (Status)) {
593     return Status;
594   }
595   //
596   // Check if the FV is write enabled
597   //
598   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
599 
600   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
601     return EFI_ACCESS_DENIED;
602   }
603   //
604   // Perform boundary checks and adjust NumBytes
605   //
606   if (BlockOffset > LbaLength) {
607     return EFI_INVALID_PARAMETER;
608   }
609 
610   if (LbaLength < (*NumBytes + BlockOffset)) {
611     *NumBytes = (UINT32) (LbaLength - BlockOffset);
612     Status    = EFI_BAD_BUFFER_SIZE;
613   }
614 
615   ReturnStatus = FlashFdWrite (
616                   LbaAddress + BlockOffset,
617                   FwhInstance,
618                   NumBytes,
619                   Buffer
620                   );
621   if (EFI_ERROR (ReturnStatus)) {
622     return ReturnStatus;
623   }
624 
625   return Status;
626 }
627 
628 EFI_STATUS
FvbEraseBlock(IN UINTN Instance,IN EFI_LBA Lba,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)629 FvbEraseBlock (
630   IN UINTN                                Instance,
631   IN EFI_LBA                              Lba,
632   IN ESAL_FWB_GLOBAL                      *Global,
633   IN BOOLEAN                              Virtual
634   )
635 /*++
636 
637 Routine Description:
638   Erases and initializes a firmware volume block
639 
640 Arguments:
641   Instance              - The FV instance to be erased
642   Lba                   - The logical block index to be erased
643   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
644                           instance data
645   Virtual               - Whether CPU is in virtual or physical mode
646 
647 Returns:
648   EFI_SUCCESS           - The erase request was successfully completed
649   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
650   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
651                           could not be written. Firmware device may have been
652                           partially erased
653   EFI_INVALID_PARAMETER - Instance not found
654 
655 --*/
656 {
657 
658   EFI_FVB_ATTRIBUTES_2  Attributes;
659   UINTN                 LbaAddress;
660   EFI_FW_VOL_INSTANCE   *FwhInstance;
661   UINTN                 LbaLength;
662   EFI_STATUS            Status;
663 
664   //
665   // Find the right instance of the FVB private data
666   //
667   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
668   ASSERT_EFI_ERROR (Status);
669 
670   //
671   // Writes are enabled in the init routine itself
672   //
673   if (!FwhInstance->WriteEnabled) {
674     return EFI_ACCESS_DENIED;
675   }
676   //
677   // Check if the FV is write enabled
678   //
679   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
680 
681   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
682     return EFI_ACCESS_DENIED;
683   }
684   //
685   // Get the starting address of the block for erase. For debug reasons,
686   // LbaWriteAddress may not be the same as LbaAddress.
687   //
688   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
689   if (EFI_ERROR (Status)) {
690     return Status;
691   }
692 
693   return FlashFdErase (
694           LbaAddress,
695           FwhInstance,
696           LbaLength
697           );
698 }
699 
700 EFI_STATUS
FvbSetVolumeAttributes(IN UINTN Instance,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)701 FvbSetVolumeAttributes (
702   IN UINTN                                Instance,
703   IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes,
704   IN ESAL_FWB_GLOBAL                      *Global,
705   IN BOOLEAN                              Virtual
706   )
707 /*++
708 
709 Routine Description:
710   Modifies the current settings of the firmware volume according to the
711   input parameter, and returns the new setting of the volume
712 
713 Arguments:
714   Instance              - The FV instance whose attributes is going to be
715                           modified
716   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
717                           containing the desired firmware volume settings.
718                           On successful return, it contains the new settings
719                           of the firmware volume
720   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
721                           instance data
722   Virtual               - Whether CPU is in virtual or physical mode
723 
724 Returns:
725   EFI_SUCCESS           - Successfully returns
726   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
727   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
728                           in conflict with the capabilities as declared in the
729                           firmware volume header
730 
731 --*/
732 {
733   EFI_FW_VOL_INSTANCE   *FwhInstance;
734   EFI_FVB_ATTRIBUTES_2  OldAttributes;
735   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
736   UINT32                Capabilities;
737   UINT32                OldStatus;
738   UINT32                NewStatus;
739   EFI_STATUS            Status;
740 
741   //
742   // Find the right instance of the FVB private data
743   //
744   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
745   ASSERT_EFI_ERROR (Status);
746 
747   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
748   OldAttributes = *AttribPtr;
749   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
750   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
751   NewStatus     = *Attributes & EFI_FVB2_STATUS;
752 
753   //
754   // If firmware volume is locked, no status bit can be updated
755   //
756   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
757     if (OldStatus ^ NewStatus) {
758       return EFI_ACCESS_DENIED;
759     }
760   }
761   //
762   // Test read disable
763   //
764   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
765     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
766       return EFI_INVALID_PARAMETER;
767     }
768   }
769   //
770   // Test read enable
771   //
772   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
773     if (NewStatus & EFI_FVB2_READ_STATUS) {
774       return EFI_INVALID_PARAMETER;
775     }
776   }
777   //
778   // Test write disable
779   //
780   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
781     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
782       return EFI_INVALID_PARAMETER;
783     }
784   }
785   //
786   // Test write enable
787   //
788   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
789     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
790       return EFI_INVALID_PARAMETER;
791     }
792   }
793   //
794   // Test lock
795   //
796   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
797     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
798       return EFI_INVALID_PARAMETER;
799     }
800   }
801 
802   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
803   *AttribPtr  = (*AttribPtr) | NewStatus;
804   *Attributes = *AttribPtr;
805 
806   return EFI_SUCCESS;
807 }
808 //
809 // FVB protocol APIs
810 //
811 EFI_STATUS
812 EFIAPI
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)813 FvbProtocolGetPhysicalAddress (
814   IN  CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
815   OUT       EFI_PHYSICAL_ADDRESS                        *Address
816   )
817 /*++
818 
819 Routine Description:
820 
821   Retrieves the physical address of the device.
822 
823 Arguments:
824 
825   This                  - Calling context
826   Address               - Output buffer containing the address.
827 
828 Returns:
829 
830 Returns:
831   EFI_SUCCESS           - Successfully returns
832 
833 --*/
834 {
835   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
836 
837   FvbDevice = FVB_DEVICE_FROM_THIS (This);
838 
839   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
840 }
841 
842 EFI_STATUS
843 EFIAPI
FvbProtocolGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumOfBlocks)844 FvbProtocolGetBlockSize (
845   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL           *This,
846   IN  EFI_LBA                                     Lba,
847   OUT UINTN                                       *BlockSize,
848   OUT UINTN                                       *NumOfBlocks
849   )
850 /*++
851 
852 Routine Description:
853   Retrieve the size of a logical block
854 
855 Arguments:
856   This                  - Calling context
857   Lba                   - Indicates which block to return the size for.
858   BlockSize             - A pointer to a caller allocated UINTN in which
859                           the size of the block is returned
860   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
861                           number of consecutive blocks starting with Lba is
862                           returned. All blocks in this range have a size of
863                           BlockSize
864 
865 Returns:
866   EFI_SUCCESS           - The firmware volume was read successfully and
867                           contents are in Buffer
868 
869 --*/
870 {
871   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
872 
873   FvbDevice = FVB_DEVICE_FROM_THIS (This);
874 
875   return FvbGetLbaAddress (
876           FvbDevice->Instance,
877           Lba,
878           NULL,
879           BlockSize,
880           NumOfBlocks,
881           mFvbModuleGlobal,
882           EfiGoneVirtual ()
883           );
884 }
885 
886 EFI_STATUS
887 EFIAPI
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)888 FvbProtocolGetAttributes (
889   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
890   OUT      EFI_FVB_ATTRIBUTES_2                        *Attributes
891   )
892 /*++
893 
894 Routine Description:
895     Retrieves Volume attributes.  No polarity translations are done.
896 
897 Arguments:
898     This                - Calling context
899     Attributes          - output buffer which contains attributes
900 
901 Returns:
902   EFI_SUCCESS           - Successfully returns
903 
904 --*/
905 {
906   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
907 
908   FvbDevice = FVB_DEVICE_FROM_THIS (This);
909 
910   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
911 }
912 
913 EFI_STATUS
914 EFIAPI
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)915 FvbProtocolSetAttributes (
916   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
917   IN OUT   EFI_FVB_ATTRIBUTES_2                     *Attributes
918   )
919 /*++
920 
921 Routine Description:
922   Sets Volume attributes. No polarity translations are done.
923 
924 Arguments:
925   This                  - Calling context
926   Attributes            - output buffer which contains attributes
927 
928 Returns:
929   EFI_SUCCESS           - Successfully returns
930 
931 --*/
932 {
933   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
934 
935   FvbDevice = FVB_DEVICE_FROM_THIS (This);
936 
937   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
938 }
939 
940 EFI_STATUS
941 EFIAPI
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)942 FvbProtocolEraseBlocks (
943   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
944   ...
945   )
946 /*++
947 
948 Routine Description:
949 
950   The EraseBlock() function erases one or more blocks as denoted by the
951   variable argument list. The entire parameter list of blocks must be verified
952   prior to erasing any blocks.  If a block is requested that does not exist
953   within the associated firmware volume (it has a larger index than the last
954   block of the firmware volume), the EraseBlock() function must return
955   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
956 
957 Arguments:
958   This                  - Calling context
959   ...                   - Starting LBA followed by Number of Lba to erase.
960                           a -1 to terminate the list.
961 
962 Returns:
963   EFI_SUCCESS           - The erase request was successfully completed
964   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
965   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
966                           could not be written. Firmware device may have been
967                           partially erased
968 
969 --*/
970 {
971   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
972   EFI_FW_VOL_INSTANCE     *FwhInstance;
973   UINTN                   NumOfBlocks;
974   VA_LIST                 args;
975   EFI_LBA                 StartingLba;
976   UINTN                   NumOfLba;
977   EFI_STATUS              Status;
978 
979   FvbDevice = FVB_DEVICE_FROM_THIS (This);
980 
981   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
982   ASSERT_EFI_ERROR (Status);
983 
984   NumOfBlocks = FwhInstance->NumOfBlocks;
985 
986   VA_START (args, This);
987 
988   do {
989     StartingLba = VA_ARG (args, EFI_LBA);
990     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
991       break;
992     }
993 
994     NumOfLba = VA_ARG (args, UINT32);
995 
996     //
997     // Check input parameters
998     //
999     if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
1000       VA_END (args);
1001       return EFI_INVALID_PARAMETER;
1002     }
1003   } while (1);
1004 
1005   VA_END (args);
1006 
1007   VA_START (args, This);
1008   do {
1009     StartingLba = VA_ARG (args, EFI_LBA);
1010     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1011       break;
1012     }
1013 
1014     NumOfLba = VA_ARG (args, UINT32);
1015 
1016     while (NumOfLba > 0) {
1017       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
1018       if (EFI_ERROR (Status)) {
1019         VA_END (args);
1020         return Status;
1021       }
1022 
1023       StartingLba++;
1024       NumOfLba--;
1025     }
1026 
1027   } while (1);
1028 
1029   VA_END (args);
1030 
1031   return EFI_SUCCESS;
1032 }
1033 
1034 EFI_STATUS
1035 EFIAPI
FvbProtocolWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)1036 FvbProtocolWrite (
1037   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *This,
1038   IN EFI_LBA                                      Lba,
1039   IN UINTN                                        Offset,
1040   IN OUT UINTN                                    *NumBytes,
1041   IN UINT8                                        *Buffer
1042   )
1043 /*++
1044 
1045 Routine Description:
1046 
1047   Writes data beginning at Lba:Offset from FV. The write terminates either
1048   when *NumBytes of data have been written, or when a block boundary is
1049   reached.  *NumBytes is updated to reflect the actual number of bytes
1050   written. The write opertion does not include erase. This routine will
1051   attempt to write only the specified bytes. If the writes do not stick,
1052   it will return an error.
1053 
1054 Arguments:
1055   This                  - Calling context
1056   Lba                   - Block in which to begin write
1057   Offset                - Offset in the block at which to begin write
1058   NumBytes              - On input, indicates the requested write size. On
1059                           output, indicates the actual number of bytes written
1060   Buffer                - Buffer containing source data for the write.
1061 
1062 Returns:
1063   EFI_SUCCESS           - The firmware volume was written successfully
1064   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
1065                           NumBytes contains the total number of bytes
1066                           actually written
1067   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
1068   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1069                           could not be written
1070   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1071 
1072 --*/
1073 {
1074 
1075   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1076 
1077   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1078 
1079   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1080 }
1081 
1082 EFI_STATUS
1083 EFIAPI
FvbProtocolRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)1084 FvbProtocolRead (
1085   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *This,
1086   IN EFI_LBA                                      Lba,
1087   IN UINTN                                        Offset,
1088   IN OUT UINTN                                    *NumBytes,
1089   IN UINT8                                        *Buffer
1090   )
1091 /*++
1092 
1093 Routine Description:
1094 
1095   Reads data beginning at Lba:Offset from FV. The Read terminates either
1096   when *NumBytes of data have been read, or when a block boundary is
1097   reached.  *NumBytes is updated to reflect the actual number of bytes
1098   written. The write opertion does not include erase. This routine will
1099   attempt to write only the specified bytes. If the writes do not stick,
1100   it will return an error.
1101 
1102 Arguments:
1103   This                  - Calling context
1104   Lba                   - Block in which to begin Read
1105   Offset                - Offset in the block at which to begin Read
1106   NumBytes              - On input, indicates the requested write size. On
1107                           output, indicates the actual number of bytes Read
1108   Buffer                - Buffer containing source data for the Read.
1109 
1110 Returns:
1111   EFI_SUCCESS           - The firmware volume was read successfully and
1112                           contents are in Buffer
1113   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
1114                           NumBytes contains the total number of bytes returned
1115                           in Buffer
1116   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
1117   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1118                           could not be read
1119   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1120 
1121 --*/
1122 {
1123 
1124   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1125 
1126   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1127 
1128   return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1129 }
1130 
1131 EFI_STATUS
ValidateFvHeader(EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)1132 ValidateFvHeader (
1133   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
1134   )
1135 /*++
1136 
1137 Routine Description:
1138   Check the integrity of firmware volume header
1139 
1140 Arguments:
1141   FwVolHeader           - A pointer to a firmware volume header
1142 
1143 Returns:
1144   EFI_SUCCESS           - The firmware volume is consistent
1145   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
1146 
1147 --*/
1148 {
1149   UINT16  *Ptr;
1150   UINT16  HeaderLength;
1151   UINT16  Checksum;
1152 
1153   //
1154   // Verify the header revision, header signature, length
1155   // Length of FvBlock cannot be 2**64-1
1156   // HeaderLength cannot be an odd number
1157   //
1158   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1159       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1160       (FwVolHeader->FvLength == ((UINTN) -1)) ||
1161       ((FwVolHeader->HeaderLength & 0x01) != 0)
1162       ) {
1163     return EFI_NOT_FOUND;
1164   }
1165   //
1166   // Verify the header checksum
1167   //
1168   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
1169   Ptr           = (UINT16 *) FwVolHeader;
1170   Checksum      = 0;
1171   while (HeaderLength > 0) {
1172     Checksum = Checksum + (*Ptr);
1173     HeaderLength--;
1174     Ptr++;
1175   }
1176 
1177   if (Checksum != 0) {
1178     return EFI_NOT_FOUND;
1179   }
1180 
1181   return EFI_SUCCESS;
1182 }
1183 
1184 
1185 EFI_STATUS
GetFvbHeader(IN OUT EFI_PEI_HOB_POINTERS * HobList,OUT EFI_FIRMWARE_VOLUME_HEADER ** FwVolHeader,OUT EFI_PHYSICAL_ADDRESS * BaseAddress OPTIONAL,OUT UINT32 * VolumeId OPTIONAL,OUT CHAR16 ** MappedFile OPTIONAL,OUT UINT32 * ActuralSize OPTIONAL,OUT UINT32 * Offset OPTIONAL,OUT BOOLEAN * WriteBack OPTIONAL)1186 GetFvbHeader (
1187   IN OUT EFI_PEI_HOB_POINTERS           *HobList,
1188   OUT    EFI_FIRMWARE_VOLUME_HEADER     **FwVolHeader,
1189   OUT    EFI_PHYSICAL_ADDRESS           *BaseAddress     OPTIONAL,
1190   OUT    UINT32                         *VolumeId        OPTIONAL,
1191   OUT    CHAR16                         **MappedFile     OPTIONAL,
1192   OUT    UINT32                         *ActuralSize     OPTIONAL,
1193   OUT    UINT32                         *Offset          OPTIONAL,
1194   OUT    BOOLEAN                        *WriteBack       OPTIONAL
1195   )
1196 {
1197   EFI_STATUS                  Status;
1198   EFI_FLASH_MAP_FS_ENTRY_DATA *FlashMapEntry;
1199   EFI_FLASH_SUBAREA_ENTRY     *FlashMapSubEntry;
1200 
1201   Status        = EFI_SUCCESS;
1202   *FwVolHeader  = NULL;
1203   TRY_ASSIGN (WriteBack, FALSE);
1204 
1205   DEBUG ((EFI_D_INFO, "Hob start is 0x%x\n", (UINTN)(*HobList).Raw));
1206   (*HobList).Raw = GetNextGuidHob (&gEfiFlashMapHobGuid, (*HobList).Raw);
1207   if ((*HobList).Raw == NULL) {
1208     return EFI_NOT_FOUND;
1209   }
1210 
1211   FlashMapEntry     = (EFI_FLASH_MAP_FS_ENTRY_DATA *) GET_GUID_HOB_DATA ((*HobList).Guid);
1212   FlashMapSubEntry  = &FlashMapEntry->Entries[0];
1213 
1214   //
1215   // Check if it is a "FVB" area
1216   //
1217   if (!CompareGuid (&FlashMapSubEntry->FileSystem, &gEfiFirmwareVolumeBlockProtocolGuid)) {
1218     return Status;
1219   }
1220   //
1221   // Check if it is a "real" flash
1222   //
1223   if (FlashMapSubEntry->Attributes != (EFI_FLASH_AREA_FV | EFI_FLASH_AREA_MEMMAPPED_FV)) {
1224     return Status;
1225   }
1226 
1227   TRY_ASSIGN (BaseAddress, FlashMapSubEntry->Base);
1228 
1229   //
1230   // Cast buffer to FLASH_AREA_INFO to get extra information related to the special FVB driver
1231   //
1232   TRY_ASSIGN (VolumeId,    FlashMapEntry->VolumeId);
1233   TRY_ASSIGN (ActuralSize, FlashMapEntry->ActuralSize);
1234   TRY_ASSIGN (MappedFile, ((CHAR16 *) FlashMapEntry->FilePath));
1235   TRY_ASSIGN (Offset,      FlashMapEntry->Offset);
1236 
1237   DEBUG ((
1238     EFI_D_INFO,
1239     "FlashMap HOB: BaseAddress = 0x%x, Length = 0x%x, ActuralLength = 0x%x, Offset = 0x%x\n",
1240     (UINTN) FlashMapSubEntry->Base, (UINTN) FlashMapSubEntry->Length,
1241     (UINTN) FlashMapEntry->ActuralSize, (UINTN) FlashMapEntry->Offset
1242   ));
1243   DEBUG ((
1244     EFI_D_INFO,
1245     "FlashMap HOB: VolumeId = 0x%lx, MappedFile = %s\n",
1246     (UINTN) FlashMapEntry->VolumeId, (UINTN) FlashMapEntry->FilePath
1247   ));
1248   *FwVolHeader  = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (FlashMapSubEntry->Base);
1249   Status        = ValidateFvHeader (*FwVolHeader);
1250   if (EFI_ERROR (Status)) {
1251     //
1252     // Get FvbInfo
1253     //
1254     TRY_ASSIGN (WriteBack, TRUE);
1255     Status = GetFvbInfo (FlashMapSubEntry->Length, FwVolHeader);
1256     DEBUG ((EFI_D_ERROR, "Fvb: FV header invalid, GetFvbInfo - %r\n", Status));
1257     ASSERT_EFI_ERROR (Status);
1258   }
1259 
1260   return EFI_SUCCESS;
1261 }
1262 
1263 VOID
1264 EFIAPI
OnSimpleFileSystemInstall(IN EFI_EVENT Event,IN VOID * Context)1265 OnSimpleFileSystemInstall (
1266   IN EFI_EVENT        Event,
1267   IN VOID             *Context
1268   )
1269 {
1270   EFI_STATUS                Status;
1271   UINTN                     HandleSize;
1272   EFI_HANDLE                Handle;
1273   UINTN                     Instance;
1274   EFI_DEVICE_PATH_PROTOCOL  *Device;
1275   EFI_FILE_PROTOCOL         *File;
1276   EFI_FW_VOL_INSTANCE       *FwhInstance;
1277   while (TRUE) {
1278     HandleSize = sizeof (EFI_HANDLE);
1279     Status = gBS->LocateHandle (
1280                     ByRegisterNotify,
1281                     NULL,
1282                     mSFSRegistration,
1283                     &HandleSize,
1284                     &Handle
1285                     );
1286     if (Status == EFI_NOT_FOUND) {
1287       break;
1288     }
1289     DEBUG ((EFI_D_ERROR, "Fwh: New FileSystem Installed!\n"));
1290     ASSERT_EFI_ERROR (Status);
1291     //
1292     // Check if this is the storage we care about, and store it in FwhInstance
1293     //
1294     for (Instance = 0; Instance < mFvbModuleGlobal->NumFv; ++Instance) {
1295       Status = GetFvbInstance (Instance, mFvbModuleGlobal, &FwhInstance, FALSE);
1296       ASSERT_EFI_ERROR (Status);
1297 
1298       if (FwhInstance->MappedFile[0] == L'\0') {
1299         //
1300         // The instance of FVB isn't mapped to file.
1301         //
1302         continue;
1303       }
1304 
1305       if ((FwhInstance->Device != NULL) &&
1306           !EFI_ERROR (CheckStoreExists (FwhInstance->Device))
1307           ) {
1308         //
1309         // The instance of FVB has already associated to a device
1310         //  and the device is not removed from system.
1311         //
1312         DEBUG ((
1313               EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Already mapped, Skip!\n",
1314               (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1315               (UINTN) FwhInstance->Offset
1316               ));
1317         continue;
1318       }
1319 
1320       Status = CheckStore (Handle, FwhInstance->VolumeId, &Device);
1321       if (!EFI_ERROR (Status)) {
1322         //
1323         // Write back memory content to file
1324         //
1325         Status = FileOpen (Device, FwhInstance->MappedFile, &File, EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ | EFI_FILE_MODE_CREATE);
1326         ASSERT_EFI_ERROR (Status);
1327         if (!EFI_ERROR (Status)) {
1328           DEBUG ((
1329                 EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Write back to mapped file!\n",
1330                 (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1331                 (UINTN) FwhInstance->Offset
1332                 ));
1333           Status = FileWrite (
1334                      File,
1335                      0,
1336                      FwhInstance->FvBase[FVB_PHYSICAL] + FwhInstance->Offset,
1337                      FwhInstance->ActuralSize - FwhInstance->Offset
1338                      );
1339           ASSERT_EFI_ERROR (Status);
1340           if (!EFI_ERROR (Status)) {
1341             if (FwhInstance->Device != NULL) {
1342               gBS->FreePool (FwhInstance->Device);
1343             }
1344             FwhInstance->Device = Device;
1345             DEBUG ((
1346                   EFI_D_ERROR, "Fwh: MappedFile FVB (0x%x:0x%x) - Mapped!\n",
1347                   (UINTN) FwhInstance->FvBase[FVB_PHYSICAL],
1348                   (UINTN) FwhInstance->Offset
1349                   ));
1350           }
1351           FileClose (File);
1352         }
1353       }
1354     }
1355   }
1356 }
1357 
1358 VOID
FvbInstallSfsNotify(VOID)1359 FvbInstallSfsNotify (
1360   VOID
1361 )
1362 {
1363   EFI_STATUS Status;
1364   EFI_EVENT  Event;
1365 
1366   Status = gBS->CreateEvent (
1367                   EVT_NOTIFY_SIGNAL,
1368                   TPL_CALLBACK,
1369                   OnSimpleFileSystemInstall,
1370                   NULL,
1371                   &Event
1372                   );
1373   ASSERT_EFI_ERROR (Status);
1374 
1375   Status = gBS->RegisterProtocolNotify (
1376                   &gEfiSimpleFileSystemProtocolGuid,
1377                   Event,
1378                   &mSFSRegistration
1379                   );
1380   ASSERT_EFI_ERROR (Status);
1381 }
1382 
1383 
1384 EFI_STATUS
1385 EFIAPI
FvbInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1386 FvbInitialize (
1387   IN EFI_HANDLE         ImageHandle,
1388   IN EFI_SYSTEM_TABLE   *SystemTable
1389   )
1390 /*++
1391 
1392 Routine Description:
1393   This function does common initialization for FVB services
1394 
1395 Arguments:
1396 
1397 Returns:
1398 
1399 --*/
1400 {
1401   EFI_STATUS                          Status;
1402   EFI_FW_VOL_INSTANCE                 *FwhInstance;
1403   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
1404   EFI_PEI_HOB_POINTERS                FirmwareVolumeHobList;
1405   UINT32                              BufferSize;
1406   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
1407   UINTN                               LbaAddress;
1408   EFI_HANDLE                          FwbHandle;
1409   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
1410   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
1411   EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
1412   FV_DEVICE_PATH                      TempFvbDevicePathData;
1413   UINT32                              MaxLbaSize;
1414   EFI_PHYSICAL_ADDRESS                BaseAddress;
1415   UINT32                              VolumeId;
1416   CHAR16                              *MappedFile;
1417   UINT32                              ActuralSize;
1418   UINT32                              Offset;
1419   BOOLEAN                             WriteBack;
1420   UINTN                               NumOfBlocks;
1421   UINTN                               HeaderLength;
1422   BOOLEAN                             InstallSfsNotify;
1423 
1424   HeaderLength     = 0;
1425   InstallSfsNotify = FALSE;
1426 
1427   //
1428   // Allocate runtime services data for global variable, which contains
1429   // the private data of all firmware volume block instances
1430   //
1431   Status = gBS->AllocatePool (
1432                   EfiRuntimeServicesData,
1433                   sizeof (ESAL_FWB_GLOBAL),
1434                   &mFvbModuleGlobal
1435                   );
1436   ASSERT_EFI_ERROR (Status);
1437   //
1438   // Calculate the total size for all firmware volume block instances
1439   //
1440   BufferSize            = 0;
1441   FirmwareVolumeHobList.Raw = GetHobList();
1442   do {
1443     Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, NULL, NULL, NULL, NULL, NULL, NULL);
1444     if (EFI_ERROR (Status)) {
1445       break;
1446     }
1447     FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
1448 
1449     if (FwVolHeader) {
1450       BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1451     }
1452   } while (TRUE);
1453 
1454   //
1455   // Only need to allocate once. There is only one copy of physical memory for
1456   // the private data of each FV instance. But in virtual mode or in physical
1457   // mode, the address of the the physical memory may be different.
1458   //
1459   Status = gBS->AllocatePool (
1460                   EfiRuntimeServicesData,
1461                   BufferSize,
1462                   &mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]
1463                   );
1464   ASSERT_EFI_ERROR (Status);
1465 
1466   //
1467   // Make a virtual copy of the FvInstance pointer.
1468   //
1469   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1470   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1471 
1472   mFvbModuleGlobal->NumFv     = 0;
1473   FirmwareVolumeHobList.Raw   = GetHobList();
1474   MaxLbaSize                  = 0;
1475 
1476   //
1477   // Fill in the private data of each firmware volume block instance
1478   //
1479   do {
1480     Status = GetFvbHeader (
1481                &FirmwareVolumeHobList, &FwVolHeader,
1482                &BaseAddress, &VolumeId, &MappedFile, &ActuralSize, &Offset,
1483                &WriteBack
1484              );
1485     if (EFI_ERROR (Status)) {
1486       break;
1487     }
1488     FirmwareVolumeHobList.Raw = GET_NEXT_HOB (FirmwareVolumeHobList);
1489 
1490     if (!FwVolHeader) {
1491       continue;
1492     }
1493 
1494     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1495     FwVolHeader                       = &(FwhInstance->VolumeHeader);
1496 
1497     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1498     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
1499     FwhInstance->Device               = NULL;
1500     FwhInstance->Offset               = Offset;
1501 
1502     if (*MappedFile != '\0') {
1503       FwhInstance->VolumeId             = VolumeId;
1504       FwhInstance->ActuralSize          = ActuralSize;
1505       StrCpy (FwhInstance->MappedFile, MappedFile);
1506 
1507       InstallSfsNotify = TRUE;
1508     } else {
1509       FwhInstance->VolumeId             = (UINT32) -1;
1510       FwhInstance->ActuralSize          = (UINT32) -1;
1511       FwhInstance->MappedFile[0]        = L'\0';
1512     }
1513 
1514     DEBUG ((EFI_D_INFO, "FirmVolume Found! BaseAddress=0x%lx, VolumeId=0x%x, MappedFile=%s, Size=0x%x\n",
1515            (UINTN) BaseAddress, VolumeId, MappedFile, ActuralSize));
1516     //
1517     // We may expose readonly FVB in future.
1518     //
1519     FwhInstance->WriteEnabled         = TRUE; // Ken: Why enable write?
1520     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1521 
1522     LbaAddress  = (UINTN) FwhInstance->FvBase[0];
1523     NumOfBlocks = 0;
1524 
1525     if (FwhInstance->WriteEnabled) {
1526       for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1527 
1528         LbaAddress += PtrBlockMapEntry->NumBlocks * PtrBlockMapEntry->Length;
1529         //
1530         // Get the maximum size of a block. The size will be used to allocate
1531         // buffer for Scratch space, the intermediate buffer for FVB extension
1532         // protocol
1533         //
1534         if (MaxLbaSize < PtrBlockMapEntry->Length) {
1535           MaxLbaSize = PtrBlockMapEntry->Length;
1536         }
1537 
1538         NumOfBlocks += PtrBlockMapEntry->NumBlocks;
1539       }
1540       //
1541       //  Write back a healthy FV header
1542       //
1543       if (WriteBack) {
1544         Status = FlashFdErase (
1545                   (UINTN) FwhInstance->FvBase[0],
1546                   FwhInstance,
1547                   FwVolHeader->BlockMap->Length
1548                   );
1549 
1550         HeaderLength = (UINTN) FwVolHeader->HeaderLength;
1551 
1552         Status = FlashFdWrite (
1553                   (UINTN) FwhInstance->FvBase[0],
1554                   FwhInstance,
1555                   (UINTN *) &HeaderLength,
1556                   (UINT8 *) FwVolHeader
1557                   );
1558 
1559         FwVolHeader->HeaderLength = (UINT16) HeaderLength;
1560 
1561         DEBUG ((EFI_D_ERROR, "Fvb (0x%x): FV header invalid, write back - %r\n", (UINTN) FwhInstance->FvBase[0], Status));
1562       }
1563     }
1564     //
1565     // The total number of blocks in the FV.
1566     //
1567     FwhInstance->NumOfBlocks = NumOfBlocks;
1568 
1569     //
1570     // Add a FVB Protocol Instance
1571     //
1572     Status = gBS->AllocatePool (
1573                     EfiRuntimeServicesData,
1574                     sizeof (EFI_FW_VOL_BLOCK_DEVICE),
1575                     &FvbDevice
1576                     );
1577     ASSERT_EFI_ERROR (Status);
1578 
1579     CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
1580 
1581     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1582     mFvbModuleGlobal->NumFv++;
1583 
1584     //
1585     // Set up the devicepath
1586     //
1587     FvbDevice->DevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1588     FvbDevice->DevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);
1589 
1590     //
1591     // Find a handle with a matching device path that has supports FW Block protocol
1592     //
1593     TempFwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) &TempFvbDevicePathData;
1594     CopyMem (TempFwbDevicePath, &FvbDevice->DevicePath, sizeof (FV_DEVICE_PATH));
1595     Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1596     if (EFI_ERROR (Status)) {
1597       //
1598       // LocateDevicePath fails so install a new interface and device path
1599       //
1600       FwbHandle = NULL;
1601       Status = gBS->InstallMultipleProtocolInterfaces (
1602                       &FwbHandle,
1603                       &gEfiFirmwareVolumeBlockProtocolGuid,
1604                       &FvbDevice->FwVolBlockInstance,
1605                       &gEfiDevicePathProtocolGuid,
1606                       &FvbDevice->DevicePath,
1607                       NULL
1608                       );
1609       ASSERT_EFI_ERROR (Status);
1610     } else if (IsDevicePathEnd (TempFwbDevicePath)) {
1611       //
1612       // Device allready exists, so reinstall the FVB protocol
1613       //
1614       Status = gBS->HandleProtocol (
1615                       FwbHandle,
1616                       &gEfiFirmwareVolumeBlockProtocolGuid,
1617                       &OldFwbInterface
1618                       );
1619       ASSERT_EFI_ERROR (Status);
1620 
1621       Status = gBS->ReinstallProtocolInterface (
1622                       FwbHandle,
1623                       &gEfiFirmwareVolumeBlockProtocolGuid,
1624                       OldFwbInterface,
1625                       &FvbDevice->FwVolBlockInstance
1626                       );
1627       ASSERT_EFI_ERROR (Status);
1628 
1629     } else {
1630       //
1631       // There was a FVB protocol on an End Device Path node
1632       //
1633       ASSERT (FALSE);
1634     }
1635 
1636     FwhInstance = (EFI_FW_VOL_INSTANCE *)
1637       (
1638         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
1639           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
1640       );
1641   } while (TRUE);
1642 
1643   //
1644   // Allocate for scratch space, an intermediate buffer for FVB extention
1645   //
1646   Status = gBS->AllocatePool (
1647                   EfiRuntimeServicesData,
1648                   MaxLbaSize,
1649                   &mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]
1650                   );
1651   ASSERT_EFI_ERROR (Status);
1652 
1653   mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
1654 
1655   if (InstallSfsNotify) {
1656     FvbInstallSfsNotify ();
1657   }
1658   return EFI_SUCCESS;
1659 }
1660