1 /** @file
2 Var Check Hii generation from FV.
3
4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
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 #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
21 EFI_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
26 EFI_GUID mAllFfGuid = ALL_FF_GUID;
27
28 #define VAR_CHECK_VFR_DRIVER_INFO_SIGNATURE SIGNATURE_32 ('V', 'D', 'R', 'I')
29
30 typedef struct {
31 UINTN Signature;
32 LIST_ENTRY Link;
33 EFI_GUID *DriverGuid;
34 } VAR_CHECK_VFR_DRIVER_INFO;
35
36 LIST_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 **/
58 EFI_STATUS
GetAddressByGuid(IN VOID * Ffs,IN EFI_GUID * Guid,IN UINTN Length,OUT UINTN ** Offset,OUT UINT8 * NumOfMatchingGuid)59 GetAddressByGuid (
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 **/
117 EFI_STATUS
SearchVfrBinInFfs(IN VOID * Ffs,IN VOID * EfiAddr,IN UINTN Length,OUT UINTN ** Offset,OUT UINT8 * NumOfMatchingOffset)118 SearchVfrBinInFfs (
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 **/
167 BOOLEAN
ParseFfs(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * Fv2,IN EFI_GUID * DriverGuid)168 ParseFfs (
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 **/
252 VOID
ParseFv(IN BOOLEAN ScanAll)253 ParseFv (
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 **/
367 VOID
CreateVfrDriverList(IN EFI_GUID * DriverGuidArray)368 CreateVfrDriverList (
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 **/
389 VOID
DestroyVfrDriverList(VOID)390 DestroyVfrDriverList (
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 **/
409 VOID
VarCheckHiiGenFromFv(VOID)410 VarCheckHiiGenFromFv (
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