1 /** @file
2 
3 Copyright (c) 2013-2015 Intel Corporation.
4 
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 
14 **/
15 
16 #include "FwBlockService.h"
17 
18 ESAL_FWB_GLOBAL         *mFvbModuleGlobal;
19 
20 EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {
21   FVB_DEVICE_SIGNATURE,  // Signature
22   //
23   // FV_DEVICE_PATH                      FvDevicePath
24   //
25   {
26     {
27       {
28         HARDWARE_DEVICE_PATH,
29         HW_MEMMAP_DP,
30         {
31           (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
32           (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
33         }
34       },
35       EfiMemoryMappedIO,
36       (EFI_PHYSICAL_ADDRESS) 0,
37       (EFI_PHYSICAL_ADDRESS) 0
38     },
39     {
40       END_DEVICE_PATH_TYPE,
41       END_ENTIRE_DEVICE_PATH_SUBTYPE,
42       {
43         END_DEVICE_PATH_LENGTH,
44         0
45       }
46     }
47   },
48   //
49   //   UEFI_FV_DEVICE_PATH                 UefiFvDevicePath
50   //
51   {
52     {
53       {
54         MEDIA_DEVICE_PATH,
55         MEDIA_PIWG_FW_VOL_DP,
56         {
57           (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
58           (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
59         }
60       },
61       { 0 }
62     },
63     {
64       END_DEVICE_PATH_TYPE,
65       END_ENTIRE_DEVICE_PATH_SUBTYPE,
66       {
67         END_DEVICE_PATH_LENGTH,
68         0
69       }
70     }
71   },
72   0,      // Instance
73   //
74   // EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  FwVolBlockInstance
75   //
76   {
77     FvbProtocolGetAttributes,
78     FvbProtocolSetAttributes,
79     FvbProtocolGetPhysicalAddress,
80     FvbProtocolGetBlockSize,
81     FvbProtocolRead,
82     FvbProtocolWrite,
83     FvbProtocolEraseBlocks,
84     NULL
85   }
86 };
87 
88 UINT32 mInSmmMode = 0;
89 EFI_SMM_SYSTEM_TABLE2*   mSmst = NULL;
90 
91 VOID
PublishFlashDeviceInfo(IN SPI_INIT_TABLE * Found)92 PublishFlashDeviceInfo (
93   IN SPI_INIT_TABLE   *Found
94   )
95 /*++
96 
97 Routine Description:
98 
99   Publish info on found flash device to other drivers via PcdSpiFlashDeviceSize.
100 
101 Arguments:
102   Found                 - Pointer to entry in mSpiInitTable for found flash part.
103 
104 Returns:
105   None
106 
107 --*/
108 {
109   EFI_STATUS  Status;
110 
111   //
112   // Publish Byte Size of found flash device.
113   //
114   Status = PcdSet32S (PcdSpiFlashDeviceSize, (UINT32)(Found->BiosStartOffset + Found->BiosSize));
115   ASSERT_EFI_ERROR (Status);
116 }
117 
118 VOID
FvbVirtualddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)119 FvbVirtualddressChangeEvent (
120   IN EFI_EVENT        Event,
121   IN VOID             *Context
122   )
123 /*++
124 
125 Routine Description:
126 
127   Fixup internal data so that EFI and SAL can be call in virtual mode.
128   Call the passed in Child Notify event and convert the mFvbModuleGlobal
129   date items to there virtual address.
130 
131   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]  - Physical copy of instance data
132   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]   - Virtual pointer to common
133                                                 instance data.
134 
135 Arguments:
136 
137   (Standard EFI notify event - EFI_EVENT_NOTIFY)
138 
139 Returns:
140 
141   None
142 
143 --*/
144 {
145   EFI_FW_VOL_INSTANCE *FwhInstance;
146   UINTN               Index;
147 
148   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvInstance[FVB_VIRTUAL]);
149 
150   //
151   // Convert the base address of all the instances
152   //
153   Index       = 0;
154   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
155   while (Index < mFvbModuleGlobal->NumFv) {
156 
157   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &FwhInstance->FvBase[FVB_VIRTUAL]);
158     //
159     // SpiWrite and SpiErase always use Physical Address instead of
160     // Virtual Address, even in Runtime. So we need not convert pointer
161     // for FvWriteBase[FVB_VIRTUAL]
162     //
163     // EfiConvertPointer (0, (VOID **) &FwhInstance->FvWriteBase[FVB_VIRTUAL]);
164     //
165     FwhInstance = (EFI_FW_VOL_INSTANCE *)
166       (
167         (UINTN) ((UINT8 *) FwhInstance) + FwhInstance->VolumeHeader.HeaderLength +
168           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
169       );
170     Index++;
171   }
172 
173   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL]);
174   //
175   // Convert SPI_PROTOCOL instance for runtime
176   //
177   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal->SpiProtocol);
178   gRT->ConvertPointer (EFI_INTERNAL_POINTER, (VOID **) &mFvbModuleGlobal);
179 }
180 
181 VOID
FvbMemWrite8(IN UINT64 Dest,IN UINT8 Byte)182 FvbMemWrite8 (
183   IN  UINT64                              Dest,
184   IN  UINT8                               Byte
185   )
186 {
187   MmioWrite8 ((UINTN)Dest, Byte);
188 
189   return ;
190 }
191 
192 EFI_STATUS
GetFvbInstance(IN UINTN Instance,IN ESAL_FWB_GLOBAL * Global,OUT EFI_FW_VOL_INSTANCE ** FwhInstance,IN BOOLEAN Virtual)193 GetFvbInstance (
194   IN  UINTN                               Instance,
195   IN  ESAL_FWB_GLOBAL                     *Global,
196   OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
197   IN BOOLEAN                              Virtual
198   )
199 /*++
200 
201 Routine Description:
202   Retrieves the physical address of a memory mapped FV
203 
204 Arguments:
205   Instance              - The FV instance whose base address is going to be
206                           returned
207   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
208                           instance data
209   FwhInstance           - The EFI_FW_VOL_INSTANCE fimrware instance structure
210   Virtual               - Whether CPU is in virtual or physical mode
211 
212 Returns:
213   EFI_SUCCESS           - Successfully returns
214   EFI_INVALID_PARAMETER - Instance not found
215 
216 --*/
217 {
218   EFI_FW_VOL_INSTANCE *FwhRecord;
219 
220   if (Instance >= Global->NumFv) {
221     return EFI_INVALID_PARAMETER;
222   }
223   //
224   // Find the right instance of the FVB private data
225   //
226   FwhRecord = Global->FvInstance[Virtual];
227   while (Instance > 0) {
228     FwhRecord = (EFI_FW_VOL_INSTANCE *)
229       (
230         (UINTN) ((UINT8 *) FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
231           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
232       );
233     Instance--;
234   }
235 
236   *FwhInstance = FwhRecord;
237 
238   return EFI_SUCCESS;
239 }
240 
241 EFI_STATUS
FvbGetPhysicalAddress(IN UINTN Instance,OUT EFI_PHYSICAL_ADDRESS * Address,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)242 FvbGetPhysicalAddress (
243   IN UINTN                                Instance,
244   OUT EFI_PHYSICAL_ADDRESS                *Address,
245   IN ESAL_FWB_GLOBAL                      *Global,
246   IN BOOLEAN                              Virtual
247   )
248 /*++
249 
250 Routine Description:
251   Retrieves the physical address of a memory mapped FV
252 
253 Arguments:
254   Instance              - The FV instance whose base address is going to be
255                           returned
256   Address               - Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
257                           that on successful return, contains the base address
258                           of the firmware volume.
259   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
260                           instance data
261   Virtual               - Whether CPU is in virtual or physical mode
262 
263 Returns:
264   EFI_SUCCESS           - Successfully returns
265   EFI_INVALID_PARAMETER - Instance not found
266 
267 --*/
268 {
269   EFI_FW_VOL_INSTANCE *FwhInstance;
270   EFI_STATUS          Status;
271 
272   FwhInstance = NULL;
273 
274   //
275   // Find the right instance of the FVB private data
276   //
277   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
278   ASSERT_EFI_ERROR (Status);
279   *Address = FwhInstance->FvBase[Virtual];
280 
281   return EFI_SUCCESS;
282 }
283 
284 EFI_STATUS
FvbGetVolumeAttributes(IN UINTN Instance,OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)285 FvbGetVolumeAttributes (
286   IN UINTN                                Instance,
287   OUT EFI_FVB_ATTRIBUTES_2                  *Attributes,
288   IN ESAL_FWB_GLOBAL                      *Global,
289   IN BOOLEAN                              Virtual
290   )
291 /*++
292 
293 Routine Description:
294   Retrieves attributes, insures positive polarity of attribute bits, returns
295   resulting attributes in output parameter
296 
297 Arguments:
298   Instance              - The FV instance whose attributes is going to be
299                           returned
300   Attributes            - Output buffer which contains attributes
301   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
302                           instance data
303   Virtual               - Whether CPU is in virtual or physical mode
304 
305 Returns:
306   EFI_SUCCESS           - Successfully returns
307   EFI_INVALID_PARAMETER - Instance not found
308 
309 --*/
310 {
311   EFI_FW_VOL_INSTANCE *FwhInstance;
312   EFI_STATUS          Status;
313 
314   FwhInstance = NULL;
315 
316   //
317   // Find the right instance of the FVB private data
318   //
319   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
320   ASSERT_EFI_ERROR (Status);
321   *Attributes = FwhInstance->VolumeHeader.Attributes;
322 
323   return EFI_SUCCESS;
324 }
325 
326 EFI_STATUS
FvbGetLbaAddress(IN UINTN Instance,IN EFI_LBA Lba,OUT UINTN * LbaAddress,OUT UINTN * LbaWriteAddress,OUT UINTN * LbaLength,OUT UINTN * NumOfBlocks,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)327 FvbGetLbaAddress (
328   IN  UINTN                               Instance,
329   IN  EFI_LBA                             Lba,
330   OUT UINTN                               *LbaAddress,
331   OUT UINTN                               *LbaWriteAddress,
332   OUT UINTN                               *LbaLength,
333   OUT UINTN                               *NumOfBlocks,
334   IN  ESAL_FWB_GLOBAL                     *Global,
335   IN  BOOLEAN                             Virtual
336   )
337 /*++
338 
339 Routine Description:
340   Retrieves the starting address of an LBA in an FV
341 
342 Arguments:
343   Instance              - The FV instance which the Lba belongs to
344   Lba                   - The logical block address
345   LbaAddress            - On output, contains the physical starting address
346                           of the Lba
347   LbaWriteAddress       - On output, contains the physical starting address
348                           of the Lba for writing
349   LbaLength             - On output, contains the length of the block
350   NumOfBlocks           - A pointer to a caller allocated UINTN in which the
351                           number of consecutive blocks starting with Lba is
352                           returned. All blocks in this range have a size of
353                           BlockSize
354   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
355                           instance data
356   Virtual               - Whether CPU is in virtual or physical mode
357 
358 Returns:
359   EFI_SUCCESS           - Successfully returns
360   EFI_INVALID_PARAMETER - Instance not found
361 
362 --*/
363 {
364   UINT32                  NumBlocks;
365   UINT32                  BlockLength;
366   UINTN                   Offset;
367   EFI_LBA                 StartLba;
368   EFI_LBA                 NextLba;
369   EFI_FW_VOL_INSTANCE     *FwhInstance;
370   EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
371   EFI_STATUS              Status;
372 
373   FwhInstance = NULL;
374 
375   //
376   // Find the right instance of the FVB private data
377   //
378   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
379   ASSERT_EFI_ERROR (Status);
380 
381   StartLba  = 0;
382   Offset    = 0;
383   BlockMap  = &(FwhInstance->VolumeHeader.BlockMap[0]);
384 
385   //
386   // Parse the blockmap of the FV to find which map entry the Lba belongs to
387   //
388   while (TRUE) {
389     NumBlocks   = BlockMap->NumBlocks;
390     BlockLength = BlockMap->Length;
391 
392     if ((NumBlocks == 0) || (BlockLength == 0)) {
393       return EFI_INVALID_PARAMETER;
394     }
395 
396     NextLba = StartLba + NumBlocks;
397 
398     //
399     // The map entry found
400     //
401     if (Lba >= StartLba && Lba < NextLba) {
402       Offset = Offset + (UINTN) MultU64x32 ((Lba - StartLba), BlockLength);
403       if (LbaAddress) {
404         *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
405       }
406 
407       if (LbaWriteAddress) {
408         *LbaWriteAddress = FwhInstance->FvWriteBase[Virtual] + Offset;
409       }
410 
411       if (LbaLength) {
412         *LbaLength = BlockLength;
413       }
414 
415       if (NumOfBlocks) {
416         *NumOfBlocks = (UINTN) (NextLba - Lba);
417       }
418 
419       return EFI_SUCCESS;
420     }
421 
422     StartLba  = NextLba;
423     Offset    = Offset + NumBlocks * BlockLength;
424     BlockMap++;
425   }
426 }
427 
428 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)429 FvbReadBlock (
430   IN UINTN                                Instance,
431   IN EFI_LBA                              Lba,
432   IN UINTN                                BlockOffset,
433   IN OUT UINTN                            *NumBytes,
434   IN UINT8                                *Buffer,
435   IN ESAL_FWB_GLOBAL                      *Global,
436   IN BOOLEAN                              Virtual
437   )
438 /*++
439 
440 Routine Description:
441   Reads specified number of bytes into a buffer from the specified block
442 
443 Arguments:
444   Instance              - The FV instance to be read from
445   Lba                   - The logical block address to be read from
446   BlockOffset           - Offset into the block at which to begin reading
447   NumBytes              - Pointer that on input contains the total size of
448                           the buffer. On output, it contains the total number
449                           of bytes read
450   Buffer                - Pointer to a caller allocated buffer that will be
451                           used to hold the data read
452   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
453                           instance data
454   Virtual               - Whether CPU is in virtual or physical mode
455 
456 Returns:
457   EFI_SUCCESS           - The firmware volume was read successfully and
458                           contents are in Buffer
459   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
460                           NumBytes contains the total number of bytes returned
461                           in Buffer
462   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
463   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
464                           could not be read
465   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
466 
467 --*/
468 {
469   EFI_FVB_ATTRIBUTES_2  Attributes;
470   UINTN               LbaAddress;
471   UINTN               LbaLength;
472   EFI_STATUS          Status;
473 
474   //
475   // Check for invalid conditions
476   //
477   if ((NumBytes == NULL) || (Buffer == NULL)) {
478     return EFI_INVALID_PARAMETER;
479   }
480 
481   if (*NumBytes == 0) {
482     return EFI_INVALID_PARAMETER;
483   }
484 
485   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, NULL, &LbaLength, NULL, Global, Virtual);
486   if (EFI_ERROR (Status)) {
487     return Status;
488   }
489   //
490   // Check if the FV is read enabled
491   //
492   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
493 
494   if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
495     return EFI_ACCESS_DENIED;
496   }
497   //
498   // Perform boundary checks and adjust NumBytes
499   //
500   if (BlockOffset > LbaLength) {
501     return EFI_INVALID_PARAMETER;
502   }
503 
504   if (LbaLength < (*NumBytes + BlockOffset)) {
505     *NumBytes = (UINT32) (LbaLength - BlockOffset);
506     Status    = EFI_BAD_BUFFER_SIZE;
507   }
508 
509   MmioReadBuffer8 (LbaAddress + BlockOffset, (UINTN) *NumBytes, Buffer);
510 
511   return Status;
512 }
513 
514 EFI_STATUS
FlashFdWrite(IN UINTN WriteAddress,IN UINTN Address,IN OUT UINTN * NumBytes,IN UINT8 * Buffer,IN UINTN LbaLength)515 FlashFdWrite (
516   IN  UINTN                               WriteAddress,
517   IN  UINTN                               Address,
518   IN OUT UINTN                            *NumBytes,
519   IN  UINT8                               *Buffer,
520   IN  UINTN                               LbaLength
521   )
522 /*++
523 
524 Routine Description:
525   Writes specified number of bytes from the input buffer to the address
526 
527 Arguments:
528 
529 Returns:
530 
531 --*/
532 {
533   EFI_STATUS  Status;
534 
535   Status = EFI_SUCCESS;
536 
537   //
538   // TODO:  Suggested that this code be "critical section"
539   //
540   WriteAddress -= ( PcdGet32 (PcdFlashAreaBaseAddress) );
541   if (mInSmmMode == 0) { // !(EfiInManagementInterrupt ())) {
542     Status = mFvbModuleGlobal->SpiProtocol->Execute (
543                                             mFvbModuleGlobal->SpiProtocol,
544                                             SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
545                                             0,                      // PrefixOpcodeIndex
546                                             TRUE,                   // DataCycle
547                                             TRUE,                   // Atomic
548                                             TRUE,                   // ShiftOut
549                                             WriteAddress,           // Address
550                                             (UINT32) (*NumBytes),   // Data Number
551                                             Buffer,
552                                             EnumSpiRegionBios
553                                             );
554 
555   } else {
556     Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
557                                             mFvbModuleGlobal->SmmSpiProtocol,
558                                             SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
559                                             0,                      // PrefixOpcodeIndex
560                                             TRUE,                   // DataCycle
561                                             TRUE,                   // Atomic
562                                             TRUE,                   // ShiftOut
563                                             WriteAddress,           // Address
564                                             (UINT32) (*NumBytes),   // Data Number
565                                             Buffer,
566                                             EnumSpiRegionBios
567                                             );
568   }
569 
570     AsmWbinvd ();
571 
572   return Status;
573 }
574 
575 EFI_STATUS
FlashFdErase(IN UINTN WriteAddress,IN UINTN Address,IN UINTN LbaLength)576 FlashFdErase (
577   IN UINTN                                WriteAddress,
578   IN UINTN                                Address,
579   IN UINTN                                LbaLength
580   )
581 /*++
582 
583 Routine Description:
584   Erase a certain block from address LbaWriteAddress
585 
586 Arguments:
587 
588 Returns:
589 
590 --*/
591 {
592   EFI_STATUS  Status;
593   UINTN       NumBytes;
594 
595   NumBytes = LbaLength;
596 
597   WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));
598   if (mInSmmMode == 0 ) { // !(EfiInManagementInterrupt ())) {
599     Status = mFvbModuleGlobal->SpiProtocol->Execute (
600                                             mFvbModuleGlobal->SpiProtocol,
601                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
602                                             0,                      // PrefixOpcodeIndex
603                                             FALSE,                  // DataCycle
604                                             TRUE,                   // Atomic
605                                             FALSE,                  // ShiftOut
606                                             WriteAddress,           // Address
607                                             0,                      // Data Number
608                                             NULL,
609                                             EnumSpiRegionBios       // SPI_REGION_TYPE
610                                             );
611   } else {
612     Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
613                                             mFvbModuleGlobal->SmmSpiProtocol,
614                                             SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
615                                             0,                      // PrefixOpcodeIndex
616                                             FALSE,                  // DataCycle
617                                             TRUE,                   // Atomic
618                                             FALSE,                  // ShiftOut
619                                             WriteAddress,           // Address
620                                             0,                      // Data Number
621                                             NULL,
622                                             EnumSpiRegionBios       // SPI_REGION_TYPE
623                                             );
624   }
625 
626   AsmWbinvd ();
627 
628   return Status;
629 }
630 
631 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)632 FvbWriteBlock (
633   IN UINTN                                Instance,
634   IN EFI_LBA                              Lba,
635   IN UINTN                                BlockOffset,
636   IN OUT UINTN                            *NumBytes,
637   IN UINT8                                *Buffer,
638   IN ESAL_FWB_GLOBAL                      *Global,
639   IN BOOLEAN                              Virtual
640   )
641 /*++
642 
643 Routine Description:
644   Writes specified number of bytes from the input buffer to the block
645 
646 Arguments:
647   Instance              - The FV instance to be written to
648   Lba                   - The starting logical block index to write to
649   BlockOffset           - Offset into the block at which to begin writing
650   NumBytes              - Pointer that on input contains the total size of
651                           the buffer. On output, it contains the total number
652                           of bytes actually written
653   Buffer                - Pointer to a caller allocated buffer that contains
654                           the source for the write
655   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
656                           instance data
657   Virtual               - Whether CPU is in virtual or physical mode
658 
659 Returns:
660   EFI_SUCCESS           - The firmware volume was written successfully
661   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
662                           NumBytes contains the total number of bytes
663                           actually written
664   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
665   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
666                           could not be written
667   EFI_INVALID_PARAMETER - Instance not found, or NumBytes, Buffer are NULL
668 
669 --*/
670 {
671   EFI_FVB_ATTRIBUTES_2  Attributes;
672   UINTN               LbaAddress;
673   UINTN               LbaWriteAddress;
674   UINTN               LbaLength;
675   EFI_FW_VOL_INSTANCE *FwhInstance;
676   EFI_STATUS          Status;
677   EFI_STATUS          ReturnStatus;
678 
679   FwhInstance = NULL;
680 
681   //
682   // Find the right instance of the FVB private data
683   //
684   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
685   ASSERT_EFI_ERROR (Status);
686 
687   //
688   // Writes are enabled in the init routine itself
689   //
690   if (!FwhInstance->WriteEnabled) {
691     return EFI_ACCESS_DENIED;
692   }
693   //
694   // Check for invalid conditions
695   //
696   if ((NumBytes == NULL) || (Buffer == NULL)) {
697     return EFI_INVALID_PARAMETER;
698   }
699 
700   if (*NumBytes == 0) {
701     return EFI_INVALID_PARAMETER;
702   }
703 
704   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
705   if (EFI_ERROR (Status)) {
706     return Status;
707   }
708   //
709   // Check if the FV is write enabled
710   //
711   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
712 
713   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
714     return EFI_ACCESS_DENIED;
715   }
716   //
717   // Perform boundary checks and adjust NumBytes
718   //
719   if (BlockOffset > LbaLength) {
720     return EFI_INVALID_PARAMETER;
721   }
722 
723   if (LbaLength < (*NumBytes + BlockOffset)) {
724     *NumBytes = (UINT32) (LbaLength - BlockOffset);
725     Status    = EFI_BAD_BUFFER_SIZE;
726   }
727 
728   ReturnStatus = FlashFdWrite (
729                   LbaWriteAddress + BlockOffset,
730                   LbaAddress,
731                   NumBytes,
732                   Buffer,
733                   LbaLength
734                   );
735   if (EFI_ERROR (ReturnStatus)) {
736     return ReturnStatus;
737   }
738 
739   return Status;
740 }
741 
742 EFI_STATUS
FvbEraseBlock(IN UINTN Instance,IN EFI_LBA Lba,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)743 FvbEraseBlock (
744   IN UINTN                                Instance,
745   IN EFI_LBA                              Lba,
746   IN ESAL_FWB_GLOBAL                      *Global,
747   IN BOOLEAN                              Virtual
748   )
749 /*++
750 
751 Routine Description:
752   Erases and initializes a firmware volume block
753 
754 Arguments:
755   Instance              - The FV instance to be erased
756   Lba                   - The logical block index to be erased
757   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
758                           instance data
759   Virtual               - Whether CPU is in virtual or physical mode
760 
761 Returns:
762   EFI_SUCCESS           - The erase request was successfully completed
763   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
764   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
765                           could not be written. Firmware device may have been
766                           partially erased
767   EFI_INVALID_PARAMETER - Instance not found
768 
769 --*/
770 {
771 
772   EFI_FVB_ATTRIBUTES_2  Attributes;
773   UINTN               LbaAddress;
774   UINTN               LbaWriteAddress;
775   EFI_FW_VOL_INSTANCE *FwhInstance;
776   UINTN               LbaLength;
777   EFI_STATUS          Status;
778   UINTN               SectorNum;
779   UINTN               Index;
780 
781   FwhInstance = NULL;
782 
783   //
784   // Find the right instance of the FVB private data
785   //
786   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
787   ASSERT_EFI_ERROR (Status);
788 
789   //
790   // Writes are enabled in the init routine itself
791   //
792   if (!FwhInstance->WriteEnabled) {
793     return EFI_ACCESS_DENIED;
794   }
795   //
796   // Check if the FV is write enabled
797   //
798   FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
799 
800   if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
801     return EFI_ACCESS_DENIED;
802   }
803   //
804   // Get the starting address of the block for erase. For debug reasons,
805   // LbaWriteAddress may not be the same as LbaAddress.
806   //
807   Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaWriteAddress, &LbaLength, NULL, Global, Virtual);
808   if (EFI_ERROR (Status)) {
809     return Status;
810   }
811 
812   SectorNum = LbaLength / SPI_ERASE_SECTOR_SIZE;
813   for (Index = 0; Index < SectorNum; Index++){
814     Status = FlashFdErase (
815                LbaWriteAddress + Index * SPI_ERASE_SECTOR_SIZE,
816                LbaAddress,
817                SPI_ERASE_SECTOR_SIZE
818                );
819     if (Status != EFI_SUCCESS){
820       break;
821     }
822   }
823 
824   return Status;
825 }
826 
827 EFI_STATUS
FvbEraseCustomBlockRange(IN UINTN Instance,IN EFI_LBA StartLba,IN UINTN OffsetStartLba,IN EFI_LBA LastLba,IN UINTN OffsetLastLba,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)828 FvbEraseCustomBlockRange (
829   IN UINTN                                Instance,
830   IN EFI_LBA                              StartLba,
831   IN UINTN                                OffsetStartLba,
832   IN EFI_LBA                              LastLba,
833   IN UINTN                                OffsetLastLba,
834   IN ESAL_FWB_GLOBAL                      *Global,
835   IN BOOLEAN                              Virtual
836   )
837 /*++
838 
839 Routine Description:
840   Erases and initializes a specified range of a firmware volume
841 
842 Arguments:
843   Instance              - The FV instance to be erased
844   StartLba              - The starting logical block index to be erased
845   OffsetStartLba        - Offset into the starting block at which to
846                           begin erasing
847   LastLba               - The last logical block index to be erased
848   OffsetStartLba        - Offset into the last block at which to end erasing
849   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
850                           instance data
851   Virtual               - Whether CPU is in virtual or physical mode
852 
853 Returns:
854   EFI_SUCCESS           - The firmware volume was erased successfully
855   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
856   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
857                           could not be written. Firmware device may have been
858                           partially erased
859   EFI_INVALID_PARAMETER - Instance not found
860 
861 --*/
862 {
863   EFI_LBA Index;
864   UINTN   LbaSize;
865   UINTN   ScratchLbaSizeData;
866 
867   //
868   // First LBA.
869   //
870   FvbGetLbaAddress (Instance, StartLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
871 
872   //
873   // Use the scratch space as the intermediate buffer to transfer data
874   // Back up the first LBA in scratch space.
875   //
876   FvbReadBlock (Instance, StartLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
877 
878   //
879   // erase now
880   //
881   FvbEraseBlock (Instance, StartLba, Global, Virtual);
882   ScratchLbaSizeData = OffsetStartLba;
883 
884   //
885   // write the data back to the first block
886   //
887   if (ScratchLbaSizeData > 0) {
888     FvbWriteBlock (Instance, StartLba, 0, &ScratchLbaSizeData, Global->FvbScratchSpace[Virtual], Global, Virtual);
889   }
890   //
891   // Middle LBAs
892   //
893   if (LastLba > (StartLba + 1)) {
894     for (Index = (StartLba + 1); Index <= (LastLba - 1); Index++) {
895       FvbEraseBlock (Instance, Index, Global, Virtual);
896     }
897   }
898   //
899   // Last LBAs, the same as first LBAs
900   //
901   if (LastLba > StartLba) {
902     FvbGetLbaAddress (Instance, LastLba, NULL, NULL, &LbaSize, NULL, Global, Virtual);
903     FvbReadBlock (Instance, LastLba, 0, &LbaSize, Global->FvbScratchSpace[Virtual], Global, Virtual);
904     FvbEraseBlock (Instance, LastLba, Global, Virtual);
905   }
906 
907   ScratchLbaSizeData = LbaSize - (OffsetStartLba + 1);
908 
909   return FvbWriteBlock (
910           Instance,
911           LastLba,
912           (OffsetLastLba + 1),
913           &ScratchLbaSizeData,
914           Global->FvbScratchSpace[Virtual],
915           Global,
916           Virtual
917           );
918 }
919 
920 EFI_STATUS
FvbSetVolumeAttributes(IN UINTN Instance,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes,IN ESAL_FWB_GLOBAL * Global,IN BOOLEAN Virtual)921 FvbSetVolumeAttributes (
922   IN UINTN                                Instance,
923   IN OUT EFI_FVB_ATTRIBUTES_2               *Attributes,
924   IN ESAL_FWB_GLOBAL                      *Global,
925   IN BOOLEAN                              Virtual
926   )
927 /*++
928 
929 Routine Description:
930   Modifies the current settings of the firmware volume according to the
931   input parameter, and returns the new setting of the volume
932 
933 Arguments:
934   Instance              - The FV instance whose attributes is going to be
935                           modified
936   Attributes            - On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
937                           containing the desired firmware volume settings.
938                           On successful return, it contains the new settings
939                           of the firmware volume
940   Global                - Pointer to ESAL_FWB_GLOBAL that contains all
941                           instance data
942   Virtual               - Whether CPU is in virtual or physical mode
943 
944 Returns:
945   EFI_SUCCESS           - Successfully returns
946   EFI_ACCESS_DENIED     - The volume setting is locked and cannot be modified
947   EFI_INVALID_PARAMETER - Instance not found, or The attributes requested are
948                           in conflict with the capabilities as declared in the
949                           firmware volume header
950 
951 --*/
952 {
953   EFI_FW_VOL_INSTANCE *FwhInstance;
954   EFI_FVB_ATTRIBUTES_2  OldAttributes;
955   EFI_FVB_ATTRIBUTES_2  *AttribPtr;
956   UINT32              Capabilities;
957   UINT32              OldStatus;
958   UINT32              NewStatus;
959   EFI_STATUS          Status;
960 
961   FwhInstance = NULL;
962 
963   //
964   // Find the right instance of the FVB private data
965   //
966   Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
967   ASSERT_EFI_ERROR (Status);
968 
969   AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);
970   OldAttributes = *AttribPtr;
971   Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;
972   OldStatus     = OldAttributes & EFI_FVB2_STATUS;
973   NewStatus     = *Attributes & EFI_FVB2_STATUS;
974 
975   //
976   // If firmware volume is locked, no status bit can be updated
977   //
978   if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
979     if (OldStatus ^ NewStatus) {
980       return EFI_ACCESS_DENIED;
981     }
982   }
983   //
984   // Test read disable
985   //
986   if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
987     if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
988       return EFI_INVALID_PARAMETER;
989     }
990   }
991   //
992   // Test read enable
993   //
994   if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
995     if (NewStatus & EFI_FVB2_READ_STATUS) {
996       return EFI_INVALID_PARAMETER;
997     }
998   }
999   //
1000   // Test write disable
1001   //
1002   if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
1003     if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
1004       return EFI_INVALID_PARAMETER;
1005     }
1006   }
1007   //
1008   // Test write enable
1009   //
1010   if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
1011     if (NewStatus & EFI_FVB2_WRITE_STATUS) {
1012       return EFI_INVALID_PARAMETER;
1013     }
1014   }
1015   //
1016   // Test lock
1017   //
1018   if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
1019     if (NewStatus & EFI_FVB2_LOCK_STATUS) {
1020       return EFI_INVALID_PARAMETER;
1021     }
1022   }
1023 
1024   *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
1025   *AttribPtr  = (*AttribPtr) | NewStatus;
1026   *Attributes = *AttribPtr;
1027 
1028   return EFI_SUCCESS;
1029 }
1030 //
1031 // FVB protocol APIs
1032 //
1033 EFI_STATUS
1034 EFIAPI
FvbProtocolGetPhysicalAddress(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_PHYSICAL_ADDRESS * Address)1035 FvbProtocolGetPhysicalAddress (
1036   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1037   OUT EFI_PHYSICAL_ADDRESS                          *Address
1038   )
1039 /*++
1040 
1041 Routine Description:
1042 
1043   Retrieves the physical address of the device.
1044 
1045 Arguments:
1046 
1047   This                  - Calling context
1048   Address               - Output buffer containing the address.
1049 
1050 Returns:
1051 
1052 Returns:
1053   EFI_SUCCESS           - Successfully returns
1054 
1055 --*/
1056 {
1057   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1058 
1059   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1060 
1061   return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, EfiGoneVirtual ());
1062 }
1063 
1064 EFI_STATUS
FvbProtocolGetBlockSize(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,OUT UINTN * BlockSize,OUT UINTN * NumOfBlocks)1065 FvbProtocolGetBlockSize (
1066   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1067   IN  EFI_LBA                                       Lba,
1068   OUT UINTN                                         *BlockSize,
1069   OUT UINTN                                         *NumOfBlocks
1070   )
1071 /*++
1072 
1073 Routine Description:
1074   Retrieve the size of a logical block
1075 
1076 Arguments:
1077   This                  - Calling context
1078   Lba                   - Indicates which block to return the size for.
1079   BlockSize             - A pointer to a caller allocated UINTN in which
1080                           the size of the block is returned
1081   NumOfBlocks           - a pointer to a caller allocated UINTN in which the
1082                           number of consecutive blocks starting with Lba is
1083                           returned. All blocks in this range have a size of
1084                           BlockSize
1085 
1086 Returns:
1087   EFI_SUCCESS           - The firmware volume was read successfully and
1088                           contents are in Buffer
1089 
1090 --*/
1091 {
1092   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1093 
1094   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1095 
1096   return FvbGetLbaAddress (
1097           FvbDevice->Instance,
1098           Lba,
1099           NULL,
1100           NULL,
1101           BlockSize,
1102           NumOfBlocks,
1103           mFvbModuleGlobal,
1104           EfiGoneVirtual ()
1105           );
1106 }
1107 
1108 EFI_STATUS
1109 EFIAPI
FvbProtocolGetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,OUT EFI_FVB_ATTRIBUTES_2 * Attributes)1110 FvbProtocolGetAttributes (
1111   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1112   OUT EFI_FVB_ATTRIBUTES_2                            *Attributes
1113   )
1114 /*++
1115 
1116 Routine Description:
1117     Retrieves Volume attributes.  No polarity translations are done.
1118 
1119 Arguments:
1120     This                - Calling context
1121     Attributes          - output buffer which contains attributes
1122 
1123 Returns:
1124   EFI_SUCCESS           - Successfully returns
1125 
1126 --*/
1127 {
1128   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1129 
1130   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1131 
1132   return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
1133 }
1134 
1135 EFI_STATUS
1136 EFIAPI
FvbProtocolSetAttributes(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN OUT EFI_FVB_ATTRIBUTES_2 * Attributes)1137 FvbProtocolSetAttributes (
1138   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1139   IN OUT EFI_FVB_ATTRIBUTES_2                         *Attributes
1140   )
1141 /*++
1142 
1143 Routine Description:
1144   Sets Volume attributes. No polarity translations are done.
1145 
1146 Arguments:
1147   This                  - Calling context
1148   Attributes            - output buffer which contains attributes
1149 
1150 Returns:
1151   EFI_SUCCESS           - Successfully returns
1152 
1153 --*/
1154 {
1155   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1156 
1157   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1158 
1159   return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
1160 }
1161 
1162 EFI_STATUS
1163 EFIAPI
FvbProtocolEraseBlocks(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,...)1164 FvbProtocolEraseBlocks (
1165   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1166   ...
1167   )
1168 /*++
1169 
1170 Routine Description:
1171 
1172   The EraseBlock() function erases one or more blocks as denoted by the
1173   variable argument list. The entire parameter list of blocks must be verified
1174   prior to erasing any blocks.  If a block is requested that does not exist
1175   within the associated firmware volume (it has a larger index than the last
1176   block of the firmware volume), the EraseBlock() function must return
1177   EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
1178 
1179 Arguments:
1180   This                  - Calling context
1181   ...                   - Starting LBA followed by Number of Lba to erase.
1182                           a -1 to terminate the list.
1183 
1184 Returns:
1185   EFI_SUCCESS           - The erase request was successfully completed
1186   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
1187   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1188                           could not be written. Firmware device may have been
1189                           partially erased
1190 
1191 --*/
1192 {
1193   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1194   EFI_FW_VOL_INSTANCE     *FwhInstance;
1195   UINTN                   NumOfBlocks;
1196   VA_LIST                 args;
1197   EFI_LBA                 StartingLba;
1198   UINTN                   NumOfLba;
1199   EFI_STATUS              Status;
1200 
1201   FwhInstance = NULL;
1202   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1203 
1204   Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
1205   ASSERT_EFI_ERROR (Status);
1206 
1207   NumOfBlocks = FwhInstance->NumOfBlocks;
1208 
1209   VA_START (args, This);
1210 
1211   do {
1212     StartingLba = VA_ARG (args, EFI_LBA);
1213     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1214       break;
1215     }
1216 
1217     NumOfLba = VA_ARG (args, UINT32);
1218 
1219     //
1220     // Check input parameters
1221     //
1222     if (NumOfLba == 0) {
1223       VA_END (args);
1224       return EFI_INVALID_PARAMETER;
1225     }
1226 
1227     if ((StartingLba + NumOfLba) > NumOfBlocks) {
1228       return EFI_INVALID_PARAMETER;
1229     }
1230   } while (TRUE);
1231 
1232   VA_END (args);
1233 
1234   VA_START (args, This);
1235   do {
1236     StartingLba = VA_ARG (args, EFI_LBA);
1237     if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
1238       break;
1239     }
1240 
1241     NumOfLba = VA_ARG (args, UINT32);
1242 
1243     while (NumOfLba > 0) {
1244       Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
1245       if (EFI_ERROR (Status)) {
1246         VA_END (args);
1247         return Status;
1248       }
1249 
1250       StartingLba++;
1251       NumOfLba--;
1252     }
1253 
1254   } while (TRUE);
1255 
1256   VA_END (args);
1257 
1258   return EFI_SUCCESS;
1259 }
1260 
1261 EFI_STATUS
1262 EFIAPI
FvbProtocolWrite(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)1263 FvbProtocolWrite (
1264   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1265   IN EFI_LBA                                        Lba,
1266   IN UINTN                                          Offset,
1267   IN OUT UINTN                                      *NumBytes,
1268   IN UINT8                                          *Buffer
1269   )
1270 /*++
1271 
1272 Routine Description:
1273 
1274   Writes data beginning at Lba:Offset from FV. The write terminates either
1275   when *NumBytes of data have been written, or when a block boundary is
1276   reached.  *NumBytes is updated to reflect the actual number of bytes
1277   written. The write opertion does not include erase. This routine will
1278   attempt to write only the specified bytes. If the writes do not stick,
1279   it will return an error.
1280 
1281 Arguments:
1282   This                  - Calling context
1283   Lba                   - Block in which to begin write
1284   Offset                - Offset in the block at which to begin write
1285   NumBytes              - On input, indicates the requested write size. On
1286                           output, indicates the actual number of bytes written
1287   Buffer                - Buffer containing source data for the write.
1288 
1289 Returns:
1290   EFI_SUCCESS           - The firmware volume was written successfully
1291   EFI_BAD_BUFFER_SIZE   - Write attempted across a LBA boundary. On output,
1292                           NumBytes contains the total number of bytes
1293                           actually written
1294   EFI_ACCESS_DENIED     - The firmware volume is in the WriteDisabled state
1295   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1296                           could not be written
1297   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1298 
1299 --*/
1300 {
1301 
1302   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1303 
1304   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1305 
1306   return FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1307 }
1308 
1309 EFI_STATUS
1310 EFIAPI
FvbProtocolRead(IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL * This,IN EFI_LBA Lba,IN UINTN Offset,IN OUT UINTN * NumBytes,IN UINT8 * Buffer)1311 FvbProtocolRead (
1312   IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
1313   IN EFI_LBA                                        Lba,
1314   IN UINTN                                          Offset,
1315   IN OUT UINTN                                      *NumBytes,
1316   IN UINT8                                          *Buffer
1317   )
1318 /*++
1319 
1320 Routine Description:
1321 
1322   Reads data beginning at Lba:Offset from FV. The Read terminates either
1323   when *NumBytes of data have been read, or when a block boundary is
1324   reached.  *NumBytes is updated to reflect the actual number of bytes
1325   written. The write opertion does not include erase. This routine will
1326   attempt to write only the specified bytes. If the writes do not stick,
1327   it will return an error.
1328 
1329 Arguments:
1330   This                  - Calling context
1331   Lba                   - Block in which to begin Read
1332   Offset                - Offset in the block at which to begin Read
1333   NumBytes              - On input, indicates the requested write size. On
1334                           output, indicates the actual number of bytes Read
1335   Buffer                - Buffer containing source data for the Read.
1336 
1337 Returns:
1338   EFI_SUCCESS           - The firmware volume was read successfully and
1339                           contents are in Buffer
1340   EFI_BAD_BUFFER_SIZE   - Read attempted across a LBA boundary. On output,
1341                           NumBytes contains the total number of bytes returned
1342                           in Buffer
1343   EFI_ACCESS_DENIED     - The firmware volume is in the ReadDisabled state
1344   EFI_DEVICE_ERROR      - The block device is not functioning correctly and
1345                           could not be read
1346   EFI_INVALID_PARAMETER - NumBytes or Buffer are NULL
1347 
1348 --*/
1349 {
1350 
1351   EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;
1352   EFI_STATUS              Status;
1353 
1354   FvbDevice = FVB_DEVICE_FROM_THIS (This);
1355   Status    = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
1356 
1357   return Status;
1358 }
1359 
1360 EFI_STATUS
ValidateFvHeader(EFI_FIRMWARE_VOLUME_HEADER * FwVolHeader)1361 ValidateFvHeader (
1362   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
1363   )
1364 /*++
1365 
1366 Routine Description:
1367   Check the integrity of firmware volume header
1368 
1369 Arguments:
1370   FwVolHeader           - A pointer to a firmware volume header
1371 
1372 Returns:
1373   EFI_SUCCESS           - The firmware volume is consistent
1374   EFI_NOT_FOUND         - The firmware volume has corrupted. So it is not an FV
1375 
1376 --*/
1377 {
1378   UINT16  *Ptr;
1379   UINT16  HeaderLength;
1380   UINT16  Checksum;
1381 
1382   //
1383   // Verify the header revision, header signature, length
1384   // Length of FvBlock cannot be 2**64-1
1385   // HeaderLength cannot be an odd number
1386   //
1387   #ifndef R864_BUILD
1388   if (((FwVolHeader->Revision != EFI_FVH_REVISION) && (FwVolHeader->Revision != EFI_FVH_REVISION)) ||
1389   #else
1390   if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
1391   #endif
1392       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
1393       (FwVolHeader->FvLength == ((UINTN) -1)) ||
1394       ((FwVolHeader->HeaderLength & 0x01) != 0)
1395       ) {
1396     return EFI_NOT_FOUND;
1397   }
1398   //
1399   // Verify the header checksum
1400   //
1401   HeaderLength  = (UINT16) (FwVolHeader->HeaderLength / 2);
1402   Ptr           = (UINT16 *) FwVolHeader;
1403   Checksum      = 0;
1404   while (HeaderLength > 0) {
1405     Checksum = Checksum + (*Ptr);
1406     Ptr++;
1407     HeaderLength--;
1408   }
1409 
1410   if (Checksum != 0) {
1411     return EFI_NOT_FOUND;
1412   }
1413 
1414   return EFI_SUCCESS;
1415 }
1416 
1417 EFI_STATUS
GetFvbHeader(VOID ** HobList,OUT EFI_FIRMWARE_VOLUME_HEADER ** FwVolHeader,OUT EFI_PHYSICAL_ADDRESS * BaseAddress,OUT BOOLEAN * WriteBack)1418 GetFvbHeader (
1419   VOID                                **HobList,
1420   OUT EFI_FIRMWARE_VOLUME_HEADER      **FwVolHeader,
1421   OUT EFI_PHYSICAL_ADDRESS            *BaseAddress,
1422   OUT BOOLEAN                         *WriteBack
1423   )
1424 {
1425   EFI_STATUS                Status;
1426 
1427   Status        = EFI_SUCCESS;
1428   *WriteBack    = FALSE;
1429 
1430   if (*FwVolHeader == NULL) {
1431     *BaseAddress = PcdGet32 (PcdFlashFvRecoveryBase);
1432   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvRecoveryBase)) {
1433     *BaseAddress = PcdGet32 (PcdFlashFvMainBase);
1434   } else if (*FwVolHeader == (VOID *)(UINTN)PcdGet32 (PcdFlashFvMainBase)) {
1435     *BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
1436   } else {
1437     return EFI_NOT_FOUND;
1438   }
1439 
1440   DEBUG((EFI_D_INFO, "Fvb base : %08x\n",*BaseAddress));
1441 
1442   *FwVolHeader  = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (*BaseAddress);
1443   Status        = ValidateFvHeader (*FwVolHeader);
1444   if (EFI_ERROR (Status)) {
1445     //
1446     // Get FvbInfo
1447     //
1448     *WriteBack  = TRUE;
1449 
1450     Status      = GetFvbInfo (*BaseAddress, FwVolHeader);
1451     DEBUG(( DEBUG_ERROR, "Through GetFvbInfo: %08x!\n",*BaseAddress));
1452 
1453     ASSERT_EFI_ERROR (Status);
1454   }
1455 
1456   return EFI_SUCCESS;
1457 }
1458 
1459 
1460 EFI_STATUS
SmmSpiInit(VOID)1461 SmmSpiInit (
1462   VOID
1463   )
1464 {
1465   UINT8       SpiStatus;
1466   UINT8       FlashIndex;
1467   UINT8       FlashID[3];
1468   EFI_STATUS  Status;
1469 
1470   //
1471   // Obtain a handle for ICH SPI Protocol
1472   //
1473   ASSERT(mSmst != NULL);
1474   if (mFvbModuleGlobal->SmmSpiProtocol == NULL){
1475     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
1476     ASSERT_EFI_ERROR(Status);
1477   }
1478   //
1479   // attempt to identify flash part and initialize spi table
1480   //
1481   for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
1482     Status = mFvbModuleGlobal->SmmSpiProtocol->Init (
1483                                                 mFvbModuleGlobal->SmmSpiProtocol,
1484                                                 &(mSpiInitTable[FlashIndex])
1485                                                 );
1486     if (!EFI_ERROR (Status)) {
1487       //
1488       // read vendor/device IDs to check if flash device is supported
1489       //
1490       Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
1491                                                   mFvbModuleGlobal->SmmSpiProtocol,
1492                                                   SPI_OPCODE_JEDEC_ID_INDEX,
1493                                                   SPI_WREN_INDEX,
1494                                                   TRUE,
1495                                                   FALSE,
1496                                                   FALSE,
1497                                                   0,
1498                                                   3,
1499                                                   FlashID,
1500                                                   EnumSpiRegionAll
1501                                                   );
1502       if (!EFI_ERROR (Status)) {
1503         if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
1504                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
1505               ((FlashID[0] == SPI_AT26DF321_ID1) &&
1506                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
1507                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
1508           //
1509           // Supported SPI device found
1510           //
1511           DEBUG (
1512               ((EFI_D_INFO),
1513               "Smm Mode: Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1514               FlashID[0],
1515               FlashID[1],
1516               FlashID[2])
1517               );
1518           break;
1519         }
1520       }
1521     }
1522   }
1523 
1524   if (FlashIndex >= EnumSpiFlashMax) {
1525     Status = EFI_UNSUPPORTED;
1526     DEBUG (
1527         (EFI_D_ERROR,
1528         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1529         FlashID[0],
1530         FlashID[1],
1531         FlashID[2])
1532         );
1533     ASSERT_EFI_ERROR (Status);
1534   }
1535 
1536   SpiStatus = 0;
1537   Status = mFvbModuleGlobal->SmmSpiProtocol->Execute (
1538                                             mFvbModuleGlobal->SmmSpiProtocol,
1539                                             SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
1540                                             1,                        // PrefixOpcodeIndex
1541                                             TRUE,                     // DataCycle
1542                                             TRUE,                     // Atomic
1543                                             TRUE,                     // ShiftOut
1544                                             0,                        // Address
1545                                             1,                        // Data Number
1546                                             &SpiStatus,
1547                                             EnumSpiRegionAll          // SPI_REGION_TYPE
1548                                             );
1549   return Status;
1550 }
1551 
1552 EFI_STATUS
SmmSpiNotificationFunction(IN CONST EFI_GUID * Protocol,IN VOID * Interface,IN EFI_HANDLE Handle)1553 SmmSpiNotificationFunction (
1554   IN CONST EFI_GUID  *Protocol,
1555   IN VOID            *Interface,
1556   IN EFI_HANDLE      Handle
1557   )
1558 {
1559   return SmmSpiInit();
1560 }
1561 
1562 
1563 VOID
1564 EFIAPI
GetFullDriverPath(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable,OUT EFI_DEVICE_PATH_PROTOCOL ** CompleteFilePath)1565 GetFullDriverPath (
1566   IN  EFI_HANDLE                  ImageHandle,
1567   IN  EFI_SYSTEM_TABLE            *SystemTable,
1568   OUT EFI_DEVICE_PATH_PROTOCOL    **CompleteFilePath
1569   )
1570 /*++
1571 
1572 Routine Description:
1573 
1574   Function is used to get the full device path for this driver.
1575 
1576 Arguments:
1577 
1578   ImageHandle        - The loaded image handle of this driver.
1579   SystemTable        - The pointer of system table.
1580   CompleteFilePath   - The pointer of returned full file path
1581 
1582 Returns:
1583 
1584   none
1585 
1586 --*/
1587 {
1588   EFI_STATUS                Status;
1589   EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
1590   EFI_DEVICE_PATH_PROTOCOL  *ImageDevicePath;
1591 
1592 
1593   Status = gBS->HandleProtocol (
1594                   ImageHandle,
1595                   &gEfiLoadedImageProtocolGuid,
1596                   (VOID **) &LoadedImage
1597                   );
1598   ASSERT_EFI_ERROR (Status);
1599 
1600   Status = gBS->HandleProtocol (
1601                   LoadedImage->DeviceHandle,
1602                   &gEfiDevicePathProtocolGuid,
1603                   (VOID *) &ImageDevicePath
1604                   );
1605   ASSERT_EFI_ERROR (Status);
1606 
1607   *CompleteFilePath = AppendDevicePath (
1608                         ImageDevicePath,
1609                         LoadedImage->FilePath
1610                         );
1611 
1612   return ;
1613 }
1614 
1615 
1616 
1617 EFI_STATUS
FvbInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1618 FvbInitialize (
1619   IN EFI_HANDLE         ImageHandle,
1620   IN EFI_SYSTEM_TABLE   *SystemTable
1621   )
1622 /*++
1623 
1624 Routine Description:
1625   This function does common initialization for FVB services
1626 
1627 Arguments:
1628 
1629 Returns:
1630 
1631 --*/
1632 {
1633   EFI_STATUS                          Status;
1634   EFI_FW_VOL_INSTANCE                 *FwhInstance;
1635   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
1636   EFI_FIRMWARE_VOLUME_HEADER          *TempFwVolHeader;
1637   VOID                                *HobList;
1638   VOID                                *FirmwareVolumeHobList;
1639   UINT32                              BufferSize;
1640   EFI_FV_BLOCK_MAP_ENTRY              *PtrBlockMapEntry;
1641   UINTN                               LbaAddress;
1642   BOOLEAN                             WriteEnabled;
1643   BOOLEAN                             WriteLocked;
1644   EFI_HANDLE                          FwbHandle;
1645   EFI_FW_VOL_BLOCK_DEVICE             *FvbDevice;
1646   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *OldFwbInterface;
1647   EFI_DEVICE_PATH_PROTOCOL            *FwbDevicePath;
1648   EFI_DEVICE_PATH_PROTOCOL            *TempFwbDevicePath;
1649   UINT32                              MaxLbaSize;
1650   EFI_PHYSICAL_ADDRESS                BaseAddress;
1651   BOOLEAN                             WriteBack;
1652   UINTN                               NumOfBlocks;
1653   UINTN                               HeaderLength;
1654   UINT8                               SpiStatus;
1655   UINT8                               FlashIndex;
1656   UINT8                               FlashID[3];
1657   EFI_DEVICE_PATH_PROTOCOL            *CompleteFilePath;
1658   UINT8                               PrefixOpcodeIndex;
1659   BOOLEAN                             InSmm;
1660   EFI_SMM_BASE2_PROTOCOL              *mSmmBase2;
1661   EFI_HANDLE                          Handle;
1662 
1663   VOID                                *Registration;
1664   EFI_EVENT                           Event;
1665 
1666   CompleteFilePath = NULL;
1667   GetFullDriverPath (ImageHandle, SystemTable, &CompleteFilePath);
1668 
1669  Status = EfiGetSystemConfigurationTable (&gEfiHobListGuid, &HobList);
1670 
1671   //
1672   // No FV HOBs found
1673   //
1674   ASSERT_EFI_ERROR (Status);
1675 
1676 
1677   //
1678   // Allocate runtime services data for global variable, which contains
1679   // the private data of all firmware volume block instances
1680   //
1681   mFvbModuleGlobal = (ESAL_FWB_GLOBAL *)AllocateRuntimeZeroPool(sizeof (ESAL_FWB_GLOBAL  ));
1682   ASSERT(mFvbModuleGlobal);
1683   mSmmBase2 = NULL;
1684   Status = gBS->LocateProtocol (
1685                   &gEfiSmmBase2ProtocolGuid,
1686                   NULL,
1687                   (VOID **) &mSmmBase2
1688                   );
1689 
1690   if (mSmmBase2 == NULL) {
1691     InSmm = FALSE;
1692   } else {
1693     mSmmBase2->InSmm (mSmmBase2, &InSmm);
1694     mSmmBase2->GetSmstLocation (mSmmBase2, &mSmst);
1695 
1696   }
1697 
1698   if (!InSmm) {
1699     mInSmmMode = 0;
1700     //
1701     // Obtain a handle for ICH SPI Protocol
1702     //
1703     Status = gBS->LocateProtocol (&gEfiSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SpiProtocol);
1704     ASSERT_EFI_ERROR (Status);
1705 
1706     //
1707     // attempt to identify flash part and initialize spi table
1708     //
1709     for (FlashIndex = 0; FlashIndex < EnumSpiFlashMax; FlashIndex++) {
1710       Status = mFvbModuleGlobal->SpiProtocol->Init (
1711                                                 mFvbModuleGlobal->SpiProtocol,
1712                                                 &(mSpiInitTable[FlashIndex])
1713                                                 );
1714       if (!EFI_ERROR (Status)) {
1715         //
1716         // read vendor/device IDs to check if flash device is supported
1717         //
1718         Status = mFvbModuleGlobal->SpiProtocol->Execute (
1719                                                   mFvbModuleGlobal->SpiProtocol,
1720                                                   SPI_OPCODE_JEDEC_ID_INDEX,
1721                                                   SPI_WREN_INDEX,
1722                                                   TRUE,
1723                                                   FALSE,
1724                                                   FALSE,
1725                                                   0,
1726                                                   3,
1727                                                   FlashID,
1728                                                   EnumSpiRegionAll
1729                                                   );
1730         if (!EFI_ERROR (Status)) {
1731           if (((FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
1732                (FlashID[2] == mSpiInitTable[FlashIndex].DeviceId1)) ||
1733               ((FlashID[0] == SPI_AT26DF321_ID1) &&
1734                (FlashID[0] == mSpiInitTable[FlashIndex].VendorId) &&
1735                (FlashID[1] == mSpiInitTable[FlashIndex].DeviceId0))) {
1736             //
1737             // Supported SPI device found
1738             //
1739             DEBUG (
1740               ((EFI_D_INFO),
1741               "Supported SPI Flash device found, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1742               FlashID[0],
1743               FlashID[1],
1744               FlashID[2])
1745               );
1746 
1747             PublishFlashDeviceInfo (&mSpiInitTable[FlashIndex]);
1748             break;
1749           }
1750         }
1751       }
1752     }
1753 
1754     if (FlashIndex >= EnumSpiFlashMax) {
1755       Status = EFI_UNSUPPORTED;
1756       DEBUG (
1757         (DEBUG_ERROR,
1758         "ERROR - Unknown SPI Flash Device, Vendor Id: 0x%02x, Device ID: 0x%02x%02x!\n",
1759         FlashID[0],
1760         FlashID[1],
1761         FlashID[2])
1762         );
1763       ASSERT_EFI_ERROR (Status);
1764     }
1765 
1766     //
1767     // Unlock all regions by writing to status register
1768     // This could be SPI device specific, need to follow the datasheet
1769     // To write to Write Status Register the Spi PrefixOpcode needs to be:
1770     //   0 for Atmel parts
1771     //   0 for Intel parts
1772     //   0 for Macronix parts
1773     //   0 for Winbond parts
1774     //   1 for SST parts
1775     SpiStatus = 0;
1776     if (FlashID[0] == SPI_SST25VF016B_ID1) {
1777       PrefixOpcodeIndex = 1;
1778     } else {
1779       PrefixOpcodeIndex = 0;
1780     }
1781     Status = mFvbModuleGlobal->SpiProtocol->Execute (
1782                                               mFvbModuleGlobal->SpiProtocol,
1783                                               SPI_OPCODE_WRITE_S_INDEX, // OpcodeIndex
1784                                               PrefixOpcodeIndex,        // PrefixOpcodeIndex
1785                                               TRUE,                     // DataCycle
1786                                               TRUE,                     // Atomic
1787                                               TRUE,                     // ShiftOut
1788                                               0,                        // Address
1789                                               1,                        // Data Number
1790                                               &SpiStatus,
1791                                               EnumSpiRegionAll          // SPI_REGION_TYPE
1792                                               );
1793 
1794 
1795   } else  {
1796     mInSmmMode = 1;
1797 
1798     Status = mSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **) &mFvbModuleGlobal->SmmSpiProtocol);
1799     if (EFI_ERROR(Status)) {
1800       Registration = NULL;
1801       Status = mSmst->SmmRegisterProtocolNotify (
1802                    &gEfiSmmSpiProtocolGuid,
1803                    SmmSpiNotificationFunction,
1804                    &Registration
1805                    );
1806     } else  {
1807       Status  = SmmSpiInit();
1808     }
1809 
1810   }
1811 
1812   //
1813   // Calculate the total size for all firmware volume block instances
1814   //
1815   BufferSize            = 0;
1816   FirmwareVolumeHobList = HobList;
1817   FwVolHeader           = NULL;
1818   do {
1819     Status = GetFvbHeader (&FirmwareVolumeHobList, &FwVolHeader, &BaseAddress, &WriteBack);
1820     if (EFI_ERROR (Status)) {
1821       break;
1822     }
1823 
1824     if (FwVolHeader) {
1825       BufferSize += (FwVolHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER));
1826     }
1827   } while (TRUE);
1828 
1829   //
1830   // Only need to allocate once. There is only one copy of physical memory for
1831   // the private data of each FV instance. But in virtual mode or in physical
1832   // mode, the address of the the physical memory may be different.
1833   //
1834   mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);
1835   ASSERT(mFvbModuleGlobal->FvInstance[FVB_PHYSICAL]);
1836   //
1837   // Make a virtual copy of the FvInstance pointer.
1838   //
1839   FwhInstance = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
1840   mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
1841 
1842   mFvbModuleGlobal->NumFv                   = 0;
1843   FirmwareVolumeHobList                     = HobList;
1844   TempFwVolHeader                           = NULL;
1845 
1846   MaxLbaSize = 0;
1847 
1848   //
1849   // Fill in the private data of each firmware volume block instance
1850   //
1851   // Foreach Fv HOB in the FirmwareVolumeHobList, loop
1852   //
1853   do {
1854     Status = GetFvbHeader (&FirmwareVolumeHobList, &TempFwVolHeader, &BaseAddress, &WriteBack);
1855     if (EFI_ERROR (Status)) {
1856       break;
1857     }
1858     FwVolHeader = TempFwVolHeader;
1859 
1860     if (!FwVolHeader) {
1861       continue;
1862     }
1863 
1864 
1865     CopyMem ((UINTN *) &(FwhInstance->VolumeHeader), (UINTN *) FwVolHeader, FwVolHeader->HeaderLength);
1866     FwVolHeader                       = &(FwhInstance->VolumeHeader);
1867 
1868     FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN) BaseAddress;
1869     FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN) BaseAddress;
1870 
1871     //
1872     // FwhInstance->FvWriteBase may not be the same as FwhInstance->FvBase
1873     //
1874     FwhInstance->FvWriteBase[FVB_PHYSICAL]  = (UINTN) BaseAddress;
1875     WriteEnabled = TRUE;
1876 
1877     //
1878     // Every pointer should have a virtual copy.
1879     //
1880     FwhInstance->FvWriteBase[FVB_VIRTUAL] = FwhInstance->FvWriteBase[FVB_PHYSICAL];
1881 
1882     FwhInstance->WriteEnabled             = WriteEnabled;
1883     EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
1884 
1885     LbaAddress  = (UINTN) FwhInstance->FvWriteBase[0];
1886     NumOfBlocks = 0;
1887     WriteLocked = FALSE;
1888 
1889     if (WriteEnabled) {
1890       for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
1891         //
1892         // Get the maximum size of a block. The size will be used to allocate
1893         // buffer for Scratch space, the intermediate buffer for FVB extension
1894         // protocol
1895         //
1896         if (MaxLbaSize < PtrBlockMapEntry->Length) {
1897           MaxLbaSize = PtrBlockMapEntry->Length;
1898         }
1899 
1900         NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
1901       }
1902       //
1903       //  Write back a healthy FV header
1904       //
1905       if (WriteBack && (!WriteLocked)) {
1906 
1907         Status = FlashFdErase (
1908                   (UINTN) FwhInstance->FvWriteBase[0],
1909                   (UINTN) BaseAddress,
1910                   FwVolHeader->BlockMap->Length
1911                   );
1912 
1913         HeaderLength = (UINTN) FwVolHeader->HeaderLength;
1914         Status = FlashFdWrite (
1915                   (UINTN) FwhInstance->FvWriteBase[0],
1916                   (UINTN) BaseAddress,
1917                   &HeaderLength,
1918                   (UINT8 *) FwVolHeader,
1919                   FwVolHeader->BlockMap->Length
1920                   );
1921 
1922       }
1923     }
1924     //
1925     // The total number of blocks in the FV.
1926     //
1927     FwhInstance->NumOfBlocks = NumOfBlocks;
1928 
1929     //
1930     // If the FV is write locked, set the appropriate attributes
1931     //
1932     if (WriteLocked) {
1933       //
1934       // write disabled
1935       //
1936       FwhInstance->VolumeHeader.Attributes &= ~EFI_FVB2_WRITE_STATUS;
1937       //
1938       // lock enabled
1939       //
1940       FwhInstance->VolumeHeader.Attributes |= EFI_FVB2_LOCK_STATUS;
1941     }
1942 
1943     //
1944     // Allocate and initialize FVB Device in a runtime data buffer
1945     //
1946     FvbDevice = AllocateRuntimeCopyPool (sizeof (EFI_FW_VOL_BLOCK_DEVICE), &mFvbDeviceTemplate);
1947     ASSERT (FvbDevice);
1948 
1949     FvbDevice->Instance = mFvbModuleGlobal->NumFv;
1950     mFvbModuleGlobal->NumFv++;
1951 
1952     //
1953     // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
1954     //
1955     if (FwVolHeader->ExtHeaderOffset == 0) {
1956       FvbDevice->FvDevicePath.MemMapDevPath.StartingAddress = BaseAddress;
1957       FvbDevice->FvDevicePath.MemMapDevPath.EndingAddress   = BaseAddress + (FwVolHeader->FvLength - 1);
1958       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->FvDevicePath;
1959     } else {
1960       CopyGuid (
1961         &FvbDevice->UefiFvDevicePath.FvDevPath.FvName,
1962         (EFI_GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
1963         );
1964       FwbDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)&FvbDevice->UefiFvDevicePath;
1965     }
1966 
1967     if (!InSmm) {
1968       //
1969       // Find a handle with a matching device path that has supports FW Block protocol
1970       //
1971       TempFwbDevicePath = FwbDevicePath;
1972       Status = gBS->LocateDevicePath (&gEfiFirmwareVolumeBlockProtocolGuid, &TempFwbDevicePath, &FwbHandle);
1973       if (EFI_ERROR (Status)) {
1974         //
1975         // LocateDevicePath fails so install a new interface and device path
1976         //
1977         FwbHandle = NULL;
1978         Status = gBS->InstallMultipleProtocolInterfaces (
1979                         &FwbHandle,
1980                         &gEfiFirmwareVolumeBlockProtocolGuid,
1981                         &FvbDevice->FwVolBlockInstance,
1982                         &gEfiDevicePathProtocolGuid,
1983                         FwbDevicePath,
1984                         NULL
1985                         );
1986         ASSERT_EFI_ERROR (Status);
1987       } else if (EfiIsDevicePathEnd (TempFwbDevicePath)) {
1988         //
1989         // Device already exists, so reinstall the FVB protocol
1990         //
1991         Status = gBS->HandleProtocol (
1992                         FwbHandle,
1993                         &gEfiFirmwareVolumeBlockProtocolGuid,
1994                         (VOID **) &OldFwbInterface
1995                         );
1996         ASSERT_EFI_ERROR (Status);
1997 
1998         Status = gBS->ReinstallProtocolInterface (
1999                         FwbHandle,
2000                         &gEfiFirmwareVolumeBlockProtocolGuid,
2001                         OldFwbInterface,
2002                         &FvbDevice->FwVolBlockInstance
2003                         );
2004         ASSERT_EFI_ERROR (Status);
2005 
2006       } else {
2007         //
2008         // There was a FVB protocol on an End Device Path node
2009         //
2010         ASSERT (FALSE);
2011       }
2012     } else {
2013       FwbHandle = NULL;
2014       Status = mSmst->SmmInstallProtocolInterface (
2015                 &FwbHandle,
2016                 &gEfiSmmFirmwareVolumeBlockProtocolGuid,
2017                 EFI_NATIVE_INTERFACE,
2018                 &FvbDevice->FwVolBlockInstance
2019                 );
2020       ASSERT_EFI_ERROR (Status);
2021     }
2022 
2023     FwhInstance = (EFI_FW_VOL_INSTANCE *)
2024       (
2025         (UINTN) ((UINT8 *) FwhInstance) + FwVolHeader->HeaderLength +
2026           (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
2027       );
2028   } while (TRUE);
2029 
2030   //
2031   // Allocate for scratch space, an intermediate buffer for FVB extention
2032   //
2033 
2034   mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL] = AllocateRuntimeZeroPool (MaxLbaSize);
2035 
2036   ASSERT (mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL]);
2037 
2038   mFvbModuleGlobal->FvbScratchSpace[FVB_VIRTUAL] = mFvbModuleGlobal->FvbScratchSpace[FVB_PHYSICAL];
2039 
2040   if (!InSmm) {
2041     Status = gBS->CreateEventEx (
2042                   EVT_NOTIFY_SIGNAL,
2043                   TPL_NOTIFY,
2044                  FvbVirtualddressChangeEvent,
2045                   NULL,
2046                   &gEfiEventVirtualAddressChangeGuid,
2047                   &Event
2048                   );
2049     ASSERT_EFI_ERROR (Status);
2050   } else {
2051     //
2052     // Inform other platform drivers that SPI device discovered and
2053     // SPI interface ready for use.
2054     //
2055     Handle = NULL;
2056     Status = gBS->InstallProtocolInterface (
2057                     &Handle,
2058                     &gEfiSmmSpiReadyProtocolGuid,
2059                     EFI_NATIVE_INTERFACE,
2060                     NULL
2061                     );
2062   }
2063   return EFI_SUCCESS;
2064 }
2065