1/**@file
2Copyright (c) 2007 - 2009, Intel Corporation. All rights reserved.<BR>
3This program and the accompanying materials
4are licensed and made available under the terms and conditions of the BSD License
5which accompanies this distribution.  The full text of the license may be found at
6http://opensource.org/licenses/bsd-license.php
7
8THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10
11Module Name:
12
13  FWBlockService.c
14
15Abstract:
16
17Revision History
18
19**/
20#include "FWBlockService.h"
21#include "EfiFlashMap.h"
22#include "FileIo.h"
23#include "FlashLayout.h"
24
25ESAL_FWB_GLOBAL       *mFvbModuleGlobal;
26VOID                  *mSFSRegistration;
27#define TRY_ASSIGN(var, value)  if(var != NULL) {*var = value;}
28
29EFI_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
68EFI_STATUS
69FlashFdWrite (
70  IN     UINTN                            Address,
71  IN     EFI_FW_VOL_INSTANCE              *FwhInstance,
72  IN OUT UINTN                            *NumBytes,
73  IN     UINT8                            *Buffer
74  )
75/*++
76
77Routine Description:
78  Writes specified number of bytes from the input buffer to the address
79
80Arguments:
81
82Returns:
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
117EFI_STATUS
118FlashFdErase (
119  IN UINTN                                Address,
120  IN EFI_FW_VOL_INSTANCE                  *FwhInstance,
121  IN UINTN                                LbaLength
122  )
123/*++
124
125Routine Description:
126  Erase a certain block from address LbaWriteAddress
127
128Arguments:
129
130Returns:
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
166VOID
167EFIAPI
168FvbVirtualddressChangeEvent (
169  IN EFI_EVENT        Event,
170  IN VOID             *Context
171  )
172/*++
173
174Routine 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
184Arguments:
185
186  (Standard EFI notify event - EFI_EVENT_NOTIFY)
187
188Returns:
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
215EFI_STATUS
216GetFvbInstance (
217  IN  UINTN                               Instance,
218  IN  ESAL_FWB_GLOBAL                     *Global,
219  OUT EFI_FW_VOL_INSTANCE                 **FwhInstance,
220  IN BOOLEAN                              Virtual
221  )
222/*++
223
224Routine Description:
225  Retrieves the physical address of a memory mapped FV
226
227Arguments:
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
235Returns:
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
261EFI_STATUS
262FvbGetPhysicalAddress (
263  IN UINTN                                Instance,
264  OUT EFI_PHYSICAL_ADDRESS                *Address,
265  IN ESAL_FWB_GLOBAL                      *Global,
266  IN BOOLEAN                              Virtual
267  )
268/*++
269
270Routine Description:
271  Retrieves the physical address of a memory mapped FV
272
273Arguments:
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
283Returns:
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
302EFI_STATUS
303FvbGetVolumeAttributes (
304  IN UINTN                                Instance,
305  OUT EFI_FVB_ATTRIBUTES_2                *Attributes,
306  IN ESAL_FWB_GLOBAL                      *Global,
307  IN BOOLEAN                              Virtual
308  )
309/*++
310
311Routine Description:
312  Retrieves attributes, insures positive polarity of attribute bits, returns
313  resulting attributes in output parameter
314
315Arguments:
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
323Returns:
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
342EFI_STATUS
343FvbGetLbaAddress (
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
354Routine Description:
355  Retrieves the starting address of an LBA in an FV
356
357Arguments:
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
371Returns:
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
436EFI_STATUS
437FvbReadBlock (
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
448Routine Description:
449  Reads specified number of bytes into a buffer from the specified block
450
451Arguments:
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
464Returns:
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}
521EFI_STATUS
522FvbWriteBlock (
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
533Routine Description:
534  Writes specified number of bytes from the input buffer to the block
535
536Arguments:
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
549Returns:
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
628EFI_STATUS
629FvbEraseBlock (
630  IN UINTN                                Instance,
631  IN EFI_LBA                              Lba,
632  IN ESAL_FWB_GLOBAL                      *Global,
633  IN BOOLEAN                              Virtual
634  )
635/*++
636
637Routine Description:
638  Erases and initializes a firmware volume block
639
640Arguments:
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
647Returns:
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
700EFI_STATUS
701FvbSetVolumeAttributes (
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
709Routine 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
713Arguments:
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
724Returns:
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//
811EFI_STATUS
812EFIAPI
813FvbProtocolGetPhysicalAddress (
814  IN  CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
815  OUT       EFI_PHYSICAL_ADDRESS                        *Address
816  )
817/*++
818
819Routine Description:
820
821  Retrieves the physical address of the device.
822
823Arguments:
824
825  This                  - Calling context
826  Address               - Output buffer containing the address.
827
828Returns:
829
830Returns:
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
842EFI_STATUS
843EFIAPI
844FvbProtocolGetBlockSize (
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
852Routine Description:
853  Retrieve the size of a logical block
854
855Arguments:
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
865Returns:
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
886EFI_STATUS
887EFIAPI
888FvbProtocolGetAttributes (
889  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL          *This,
890  OUT      EFI_FVB_ATTRIBUTES_2                        *Attributes
891  )
892/*++
893
894Routine Description:
895    Retrieves Volume attributes.  No polarity translations are done.
896
897Arguments:
898    This                - Calling context
899    Attributes          - output buffer which contains attributes
900
901Returns:
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
913EFI_STATUS
914EFIAPI
915FvbProtocolSetAttributes (
916  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL       *This,
917  IN OUT   EFI_FVB_ATTRIBUTES_2                     *Attributes
918  )
919/*++
920
921Routine Description:
922  Sets Volume attributes. No polarity translations are done.
923
924Arguments:
925  This                  - Calling context
926  Attributes            - output buffer which contains attributes
927
928Returns:
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
940EFI_STATUS
941EFIAPI
942FvbProtocolEraseBlocks (
943  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,
944  ...
945  )
946/*++
947
948Routine 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
957Arguments:
958  This                  - Calling context
959  ...                   - Starting LBA followed by Number of Lba to erase.
960                          a -1 to terminate the list.
961
962Returns:
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
1034EFI_STATUS
1035EFIAPI
1036FvbProtocolWrite (
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
1045Routine 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
1054Arguments:
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
1062Returns:
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
1082EFI_STATUS
1083EFIAPI
1084FvbProtocolRead (
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
1093Routine 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
1102Arguments:
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
1110Returns:
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
1131EFI_STATUS
1132ValidateFvHeader (
1133  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader
1134  )
1135/*++
1136
1137Routine Description:
1138  Check the integrity of firmware volume header
1139
1140Arguments:
1141  FwVolHeader           - A pointer to a firmware volume header
1142
1143Returns:
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
1185EFI_STATUS
1186GetFvbHeader (
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
1263VOID
1264EFIAPI
1265OnSimpleFileSystemInstall (
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
1358VOID
1359FvbInstallSfsNotify (
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
1384EFI_STATUS
1385EFIAPI
1386FvbInitialize (
1387  IN EFI_HANDLE         ImageHandle,
1388  IN EFI_SYSTEM_TABLE   *SystemTable
1389  )
1390/*++
1391
1392Routine Description:
1393  This function does common initialization for FVB services
1394
1395Arguments:
1396
1397Returns:
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