1/** @file
2  Var Check Hii generation from FV.
3
4Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "VarCheckHiiGen.h"
16
17// {d0bc7cb4-6a47-495f-aa11-710746da06a2}
18#define EFI_VFR_ATTRACT_GUID \
19{ 0xd0bc7cb4, 0x6a47, 0x495f, { 0xaa, 0x11, 0x71, 0x7, 0x46, 0xda, 0x6, 0xa2 } }
20
21EFI_GUID  gVfrArrayAttractGuid  = EFI_VFR_ATTRACT_GUID;
22
23#define ALL_FF_GUID \
24{ 0xFFFFFFFF, 0xFFFF, 0xFFFF, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }
25
26EFI_GUID mAllFfGuid             = ALL_FF_GUID;
27
28#define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE     SIGNATURE_32 ('V', 'D', 'R', 'I')
29
30typedef struct {
31  UINTN             Signature;
32  LIST_ENTRY        Link;
33  EFI_GUID          *DriverGuid;
34} VAR_CHECK_VFR_DRIVER_INFO;
35
36LIST_ENTRY                      mVfrDriverList = INITIALIZE_LIST_HEAD_VARIABLE (mVfrDriverList);
37
38#define VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK(a)  CR (a, VAR_CHECK_VFR_DRIVER_INFO, Link, VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE)
39
40#define MAX_MATCH_GUID_NUM      100
41
42/**
43  Get the address by Guid.
44
45  Parse the FFS and find the GUID address.
46  There may be multiple Guids matching the searched Guid.
47
48  @param Ffs                Pointer to the FFS.
49  @param Guid               Guid to find.
50  @param Length             The length of FFS.
51  @param Offset             Pointer to pointer to the offset.
52  @param NumOfMatchingGuid  The number of matching Guid.
53
54  @retval EFI_SUCCESS       One or multiple Guids matching the searched Guid.
55  @retval EFI_NOT_FOUND     No Guid matching the searched Guid.
56
57**/
58EFI_STATUS
59GetAddressByGuid (
60  IN  VOID          *Ffs,
61  IN  EFI_GUID      *Guid,
62  IN  UINTN         Length,
63  OUT UINTN         **Offset,
64  OUT UINT8         *NumOfMatchingGuid
65  )
66{
67  UINTN     LoopControl;
68  BOOLEAN   Found;
69
70  if((Ffs == NULL) || (Guid == NULL) || (Length == 0)){
71    return EFI_NOT_FOUND;
72  }
73
74  if (NumOfMatchingGuid != NULL) {
75    *NumOfMatchingGuid = 0;
76  }
77
78  Found = FALSE;
79  for (LoopControl = 0; LoopControl < Length; LoopControl++) {
80    if (CompareGuid (Guid, (EFI_GUID *) ((UINT8 *) Ffs + LoopControl))) {
81      Found = TRUE;
82      //
83      // If NumOfMatchGuid or Offset are NULL, means user only want
84      // to check whether current FFS includes this Guid or not.
85      //
86      if ((NumOfMatchingGuid != NULL) && (Offset != NULL)) {
87        if (*NumOfMatchingGuid == 0) {
88          *Offset = InternalVarCheckAllocateZeroPool (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
89          ASSERT (*Offset != NULL);
90        }
91        *(*Offset + *NumOfMatchingGuid) = LoopControl + sizeof (EFI_GUID);
92        (*NumOfMatchingGuid)++;
93      } else {
94        break;
95      }
96    }
97  }
98
99  return (Found ? EFI_SUCCESS : EFI_NOT_FOUND);
100}
101
102/**
103  Search the VfrBin Base address.
104
105  According to the known GUID gVfrArrayAttractGuid to get the base address from FFS.
106
107  @param Ffs                    Pointer to the FFS.
108  @param EfiAddr                Pointer to the EFI in FFS
109  @param Length                 The length of FFS.
110  @param Offset                 Pointer to pointer to the Addr (Offset).
111  @param NumOfMatchingOffset    The number of Addr (Offset).
112
113  @retval EFI_SUCCESS           Get the address successfully.
114  @retval EFI_NOT_FOUND         No VfrBin found.
115
116**/
117EFI_STATUS
118SearchVfrBinInFfs (
119   IN  VOID      *Ffs,
120   IN  VOID      *EfiAddr,
121   IN  UINTN     Length,
122   OUT UINTN     **Offset,
123   OUT UINT8     *NumOfMatchingOffset
124  )
125{
126  UINTN        Index;
127  EFI_STATUS   Status;
128  UINTN        VirOffValue;
129
130  if ((Ffs == NULL) || (Offset == NULL)) {
131    return EFI_NOT_FOUND;
132  }
133  Status = GetAddressByGuid (
134             Ffs,
135             &gVfrArrayAttractGuid,
136             Length,
137             Offset,
138             NumOfMatchingOffset
139             );
140  if (Status != EFI_SUCCESS) {
141    return Status;
142  }
143
144  for (Index = 0; Index < *NumOfMatchingOffset; Index++) {
145    //
146    // Got the virOffset after the GUID
147    //
148    VirOffValue = *(UINTN *) ((UINTN) Ffs + *(*Offset + Index));
149    //
150    // Transfer the offset to the VA address. One modules may own multiple VfrBin address.
151    //
152    *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
153  }
154
155  return Status;
156}
157
158/**
159  Parse FFS.
160
161  @param[in] Fv2            Pointer to Fv2 protocol.
162  @param[in] DriverGuid     Pointer to driver GUID.
163
164  @return Found the driver in the FV or not.
165
166**/
167BOOLEAN
168ParseFfs (
169  IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv2,
170  IN EFI_GUID                       *DriverGuid
171  )
172{
173  EFI_STATUS                    Status;
174  EFI_FV_FILETYPE               FoundType;
175  EFI_FV_FILE_ATTRIBUTES        FileAttributes;
176  UINT32                        AuthenticationStatus;
177  UINTN                         Size;
178  VOID                          *Buffer;
179  UINTN                         SectionSize;
180  VOID                          *SectionBuffer;
181  UINTN                         VfrBinIndex;
182  UINT8                         NumberofMatchingVfrBin;
183  UINTN                         *VfrBinBaseAddress;
184
185  Status = Fv2->ReadFile (
186                  Fv2,
187                  DriverGuid,
188                  NULL,
189                  &Size,
190                  &FoundType,
191                  &FileAttributes,
192                  &AuthenticationStatus
193                  );
194  if (EFI_ERROR (Status)) {
195    return FALSE;
196  }
197
198  Buffer = NULL;
199  Status = Fv2->ReadSection (
200                  Fv2,
201                  DriverGuid,
202                  EFI_SECTION_RAW,
203                  0, // Instance
204                  &Buffer,
205                  &Size,
206                  &AuthenticationStatus
207                  );
208   if (!EFI_ERROR (Status)) {
209     Status = SearchVfrBinInFfs (Buffer, 0, Size, &VfrBinBaseAddress, &NumberofMatchingVfrBin);
210     if (!EFI_ERROR (Status)) {
211        SectionBuffer = NULL;
212        Status = Fv2->ReadSection (
213                        Fv2,
214                        DriverGuid,
215                        EFI_SECTION_PE32,
216                        0, // Instance
217                        &SectionBuffer,
218                        &SectionSize,
219                        &AuthenticationStatus
220                        );
221        if (!EFI_ERROR (Status)) {
222          DEBUG ((EFI_D_INFO, "FfsNameGuid - %g\n", DriverGuid));
223          DEBUG ((EFI_D_INFO, "NumberofMatchingVfrBin - 0x%02x\n", NumberofMatchingVfrBin));
224
225          for (VfrBinIndex = 0; VfrBinIndex < NumberofMatchingVfrBin; VfrBinIndex++) {
226#ifdef DUMP_HII_DATA
227            DEBUG_CODE (
228              DumpHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32));
229              );
230#endif
231            VarCheckParseHiiPackage ((UINT8 *) (UINTN) SectionBuffer + VfrBinBaseAddress[VfrBinIndex] + sizeof (UINT32), TRUE);
232          }
233
234          FreePool (SectionBuffer);
235        }
236
237        InternalVarCheckFreePool (VfrBinBaseAddress);
238      }
239
240      FreePool (Buffer);
241    }
242
243   return TRUE;
244}
245
246/**
247  Parse FVs.
248
249  @param[in] ScanAll    Scan all modules in all FVs or not.
250
251**/
252VOID
253ParseFv (
254  IN BOOLEAN    ScanAll
255  )
256{
257  EFI_STATUS                    Status;
258  EFI_HANDLE                    *HandleBuffer;
259  UINTN                         HandleCount;
260  UINTN                         Index;
261  EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv2;
262  VOID                          *Key;
263  EFI_FV_FILETYPE               FileType;
264  EFI_GUID                      NameGuid;
265  EFI_FV_FILE_ATTRIBUTES        FileAttributes;
266  UINTN                         Size;
267  UINTN                         FfsIndex;
268  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
269  LIST_ENTRY                    *VfrDriverLink;
270
271  HandleBuffer = NULL;
272  Status = gBS->LocateHandleBuffer (
273                  ByProtocol,
274                  &gEfiFirmwareVolume2ProtocolGuid,
275                  NULL,
276                  &HandleCount,
277                  &HandleBuffer
278                  );
279  if (EFI_ERROR (Status)) {
280    return;
281  }
282
283  //
284  // Search all FVs
285  //
286  for (Index = 0; Index < HandleCount; Index++) {
287    DEBUG ((EFI_D_INFO, "FvIndex - %x\n", Index));
288    Status = gBS->HandleProtocol (
289                    HandleBuffer[Index],
290                    &gEfiFirmwareVolume2ProtocolGuid,
291                    (VOID **) &Fv2
292                    );
293    ASSERT_EFI_ERROR (Status);
294
295    DEBUG_CODE (
296      EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *Fvb2;
297      EFI_PHYSICAL_ADDRESS                  FvAddress;
298      UINT64                                FvSize;
299
300      Status = gBS->HandleProtocol (
301                      HandleBuffer[Index],
302                      &gEfiFirmwareVolumeBlock2ProtocolGuid,
303                      (VOID **) &Fvb2
304                      );
305      ASSERT_EFI_ERROR (Status);
306      Status = Fvb2->GetPhysicalAddress (Fvb2, &FvAddress);
307      if (!EFI_ERROR (Status)) {
308        DEBUG ((EFI_D_INFO, "FvAddress - 0x%08x\n", FvAddress));
309        FvSize = ((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvAddress)->FvLength;
310        DEBUG ((EFI_D_INFO, "FvSize    - 0x%08x\n", FvSize));
311      }
312    );
313
314    if (ScanAll) {
315      //
316      // Need to parse all modules in all FVs.
317      //
318      Key = InternalVarCheckAllocateZeroPool (Fv2->KeySize);
319      ASSERT (Key != NULL);
320
321      for (FfsIndex = 0; ; FfsIndex++) {
322        FileType = EFI_FV_FILETYPE_ALL;
323        Status = Fv2->GetNextFile (
324                        Fv2,
325                        Key,
326                        &FileType,
327                        &NameGuid,
328                        &FileAttributes,
329                        &Size
330                      );
331        if (EFI_ERROR (Status)) {
332          break;
333        }
334
335        ParseFfs (Fv2, &NameGuid);
336      }
337
338      InternalVarCheckFreePool (Key);
339    } else {
340      //
341      // Only parse drivers in the VFR drivers list.
342      //
343      VfrDriverLink = mVfrDriverList.ForwardLink;
344      while (VfrDriverLink != &mVfrDriverList) {
345        VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
346        VfrDriverLink = VfrDriverLink->ForwardLink;
347        if (ParseFfs (Fv2, VfrDriverInfo->DriverGuid)) {
348          //
349          // Found the driver in the FV.
350          //
351          RemoveEntryList (&VfrDriverInfo->Link);
352          InternalVarCheckFreePool (VfrDriverInfo);
353        }
354      }
355    }
356  }
357
358  FreePool (HandleBuffer);
359}
360
361/**
362  Create Vfr Driver List.
363
364  @param[in] DriverGuidArray    Driver Guid Array
365
366**/
367VOID
368CreateVfrDriverList (
369  IN EFI_GUID   *DriverGuidArray
370  )
371{
372  UINTN                         Index;
373  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
374
375  for (Index = 0; !IsZeroGuid (&DriverGuidArray[Index]); Index++) {
376     DEBUG ((EFI_D_INFO, "CreateVfrDriverList: %g\n", &DriverGuidArray[Index]));
377     VfrDriverInfo = InternalVarCheckAllocateZeroPool (sizeof (*VfrDriverInfo));
378     ASSERT (VfrDriverInfo != NULL);
379     VfrDriverInfo->Signature = VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE;
380     VfrDriverInfo->DriverGuid = &DriverGuidArray[Index];
381     InsertTailList (&mVfrDriverList, &VfrDriverInfo->Link);
382  }
383}
384
385/**
386  Destroy Vfr Driver List.
387
388**/
389VOID
390DestroyVfrDriverList (
391  VOID
392  )
393{
394  VAR_CHECK_VFR_DRIVER_INFO     *VfrDriverInfo;
395  LIST_ENTRY                    *VfrDriverLink;
396
397  while (mVfrDriverList.ForwardLink != &mVfrDriverList) {
398    VfrDriverLink = mVfrDriverList.ForwardLink;
399    VfrDriverInfo = VAR_CHECK_VFR_DRIVER_INFO_FROM_LINK (VfrDriverLink);
400    RemoveEntryList (&VfrDriverInfo->Link);
401    InternalVarCheckFreePool (VfrDriverInfo);
402  }
403}
404
405/**
406  Generate from FV.
407
408**/
409VOID
410VarCheckHiiGenFromFv (
411  VOID
412  )
413{
414  EFI_GUID      *DriverGuidArray;
415  BOOLEAN       ScanAll;
416
417  DEBUG ((EFI_D_INFO, "VarCheckHiiGenDxeFromFv\n"));
418
419  //
420  // Get vfr driver guid array from PCD.
421  //
422  DriverGuidArray = (EFI_GUID *) PcdGetPtr (PcdVarCheckVfrDriverGuidArray);
423
424  if (IsZeroGuid (&DriverGuidArray[0])) {
425    //
426    // No VFR driver will be parsed from FVs.
427    //
428    return;
429  }
430
431  if (CompareGuid (&DriverGuidArray[0], &mAllFfGuid)) {
432    ScanAll = TRUE;
433  } else {
434    ScanAll = FALSE;
435    CreateVfrDriverList (DriverGuidArray);
436  }
437
438  ParseFv (ScanAll);
439
440  if (!ScanAll) {
441    DestroyVfrDriverList ();
442  }
443}
444