]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/FCE/BinaryParse.c
BaseTools/FCE: Add a tool FCE
[mirror_edk2.git] / BaseTools / Source / C / FCE / BinaryParse.c
1 /** @file
2
3 The API to parse the binary.
4
5 Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #ifndef __GNUC__
11 #include "windows.h"
12 #else
13 #include <sys/types.h>
14 #include <dirent.h>
15 #include <unistd.h>
16 #endif
17 #include "BinaryParse.h"
18 #include "BinaryCreate.h"
19 #include "VariableCommon.h"
20 #include "FirmwareVolumeBufferLib.h"
21
22 extern G_EFI_FD_INFO gEfiFdInfo;
23 extern EFI_HANDLE mParsedGuidedSectionTools;
24 extern CHAR8 mInputFdName[MAX_FILENAME_LEN];
25
26 //
27 // The Guid to sign the position of Vfr and Uni array in FV
28 //
29 EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID;
30 EFI_GUID gUniStrArrayAttractGuid = EFI_UNI_STR_ATTRACT_GUID;
31 EFI_GUID gEfiSystemNvDataFvGuid = EFI_SYSTEM_NVDATA_FV_GUID;
32 EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID;
33
34 /**
35 Converts a three byte length value into a UINT32.
36
37 @param ThreeByteLength Pointer to the first of the 3 byte length.
38
39 @retval Length Size of the section
40
41 **/
42 static
43 UINT32
44 Get3ByteLength (
45 IN UINT8 *ThreeByteLength
46 )
47 {
48 UINT32 Length;
49
50 Length = 0;
51
52 if (ThreeByteLength == NULL) {
53 return 0;
54 }
55
56 Length = *((UINT32 *) ThreeByteLength);
57 Length = Length & 0x00FFFFFF;
58
59 return Length;
60 }
61
62 /**
63 Generate the unique template filename.
64 **/
65 CHAR8 *
66 GenTempFile (
67 VOID
68 )
69 {
70 CHAR8 *TemString;
71 TemString = NULL;
72 #ifndef __GNUC__
73 TemString = CloneString (tmpnam (NULL));
74 #else
75 CHAR8 tmp[] = "/tmp/fileXXXXXX";
76 UINTN Fdtmp;
77 Fdtmp = mkstemp(tmp);
78 TemString = CloneString(tmp);
79 close(Fdtmp);
80 #endif
81 return TemString;
82 }
83
84 /**
85 Check whether exist the same Ifr FFS. If not existed, return TRUE.
86
87 @param[in] FfsImage The pointer to the binary.
88 @param[in] FileSize The size of binary.
89
90 @return The string after convert.
91 **/
92 static
93 BOOLEAN
94 NotExistSameFfsIfr (
95 IN VOID *FfsImage
96 )
97 {
98 UINT32 Index;
99
100 Index = 0;
101
102 while (gEfiFdInfo.FfsArray[Index] != NULL) {
103 if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) == 0) {
104 return FALSE;
105 }
106 Index++;
107 }
108 return TRUE;
109 }
110
111 /**
112 This function returns the next larger size that meets the alignment
113 requirement specified.
114
115 @param ActualSize The size.
116 @param Alignment The desired alignment.
117
118 @retval The Occupied length
119
120 **/
121 static
122 UINT32
123 GetOccupiedSize (
124 IN UINT32 ActualSize,
125 IN UINT32 Alignment
126 )
127 {
128 UINT32 OccupiedSize;
129
130 OccupiedSize = ActualSize;
131 while ((OccupiedSize & (Alignment - 1)) != 0) {
132 OccupiedSize++;
133 }
134
135 return OccupiedSize;
136 }
137
138
139 /**
140 Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS.
141
142 @param SectionBuffer The section base address
143 @param BufferLength The length of FFS.
144 @param EfiBufferHeader The structure dual pointer to the efi informations
145
146 @retval EFI_SUCCESS The application exited normally.
147 @retval EFI_ABORTED An error occurred.
148
149 **/
150 EFI_STATUS
151 ParseSection (
152 IN BOOLEAN IsFfsOrEfi,
153 IN OUT UINT8 *SectionBuffer,
154 IN UINT32 BufferLength,
155 IN OUT EFI_SECTION_STRUCT **EfiBufferHeader
156 )
157 {
158 UINT32 ParsedLength;
159 EFI_SECTION_TYPE Type;
160 UINT8 *Ptr;
161 UINT32 SectionLength;
162 UINT8 *CompressedBuffer;
163 UINT32 CompressedLength;
164 UINT8 *UncompressedBuffer;
165 UINT32 UncompressedLength;
166 UINT8 CompressionType;
167 DECOMPRESS_FUNCTION DecompressFunction;
168 GETINFO_FUNCTION GetInfoFunction;
169 UINT32 ScratchSize;
170 UINT8 *ScratchBuffer;
171 EFI_STATUS Status;
172 UINT32 DstSize;
173 CHAR8 *ExtractionTool;
174 CHAR8 *ToolInputFile;
175 CHAR8 *ToolOutputFile;
176 CHAR8 *SystemCommandFormatString;
177 CHAR8 *SystemCommand;
178 UINT8 *ToolOutputBuffer;
179 UINT32 ToolOutputLength;
180 BOOLEAN HasDepexSection;
181
182 Ptr = NULL;
183 SectionLength = 0;
184 CompressedBuffer = NULL;
185 CompressedLength = 0;
186 UncompressedBuffer = NULL;
187 UncompressedLength = 0;
188 CompressionType = 0;
189 ScratchSize = 0;
190 ScratchBuffer = NULL;
191 Status = EFI_SUCCESS;
192 DstSize = 0;
193 ExtractionTool = NULL;
194 ToolInputFile = NULL;
195 ToolOutputFile = NULL;
196 SystemCommandFormatString = NULL;
197 SystemCommand = NULL;
198
199 //
200 // Jump the FFS header
201 //
202 if (IsFfsOrEfi) {
203 SectionBuffer = SectionBuffer + sizeof (EFI_FFS_FILE_HEADER);
204 BufferLength = BufferLength - sizeof (EFI_FFS_FILE_HEADER);
205 }
206 ParsedLength = 0;
207 HasDepexSection = FALSE;
208 ExtractionTool = NULL;
209 ToolOutputLength = 0;
210 ToolOutputBuffer = NULL;
211
212 (*EfiBufferHeader)->Length = BufferLength;
213
214 while (ParsedLength < BufferLength) {
215 Ptr = SectionBuffer + ParsedLength;
216
217 SectionLength = Get3ByteLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size);
218 Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type;
219
220 //
221 // This is sort of an odd check, but is necessary because FFS files are
222 // padded to a QWORD boundary, meaning there is potentially a whole section
223 // header worth of 0xFF bytes.
224 //
225 if ((SectionLength == 0xffffff) && (Type == 0xff)) {
226 ParsedLength += 4;
227 continue;
228 }
229
230 switch (Type) {
231
232 case EFI_SECTION_PE32:
233 case EFI_SECTION_TE:
234 //
235 //Got the correct address
236 //
237 (*EfiBufferHeader)->BufferBase = (UINTN)(Ptr + sizeof (EFI_COMMON_SECTION_HEADER));
238 return EFI_SUCCESS;
239
240 case EFI_SECTION_RAW:
241 case EFI_SECTION_PIC:
242 break;
243
244 case EFI_SECTION_USER_INTERFACE:
245 HasDepexSection = FALSE;
246 break;
247
248 case EFI_SECTION_FIRMWARE_VOLUME_IMAGE:
249 case EFI_SECTION_COMPATIBILITY16:
250 case EFI_SECTION_FREEFORM_SUBTYPE_GUID:
251 break;
252
253 case EFI_SECTION_PEI_DEPEX:
254 case EFI_SECTION_DXE_DEPEX:
255 case EFI_SECTION_SMM_DEPEX:
256 HasDepexSection = TRUE;
257 break;
258
259 case EFI_SECTION_VERSION:
260 break;
261 case EFI_SECTION_COMPRESSION:
262 UncompressedBuffer = NULL;
263 CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION);
264 UncompressedLength = ((EFI_COMPRESSION_SECTION *) Ptr)->UncompressedLength;
265 CompressionType = ((EFI_COMPRESSION_SECTION *) Ptr)->CompressionType;
266
267 if (CompressionType == EFI_NOT_COMPRESSED) {
268 if (CompressedLength != UncompressedLength) {
269 Error (
270 NULL,
271 0,
272 0,
273 "file is not compressed, but the compressed length does not match the uncompressed length",
274 NULL
275 );
276 return EFI_ABORTED;
277 }
278
279 UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
280 } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
281 GetInfoFunction = EfiGetInfo;
282 DecompressFunction = EfiDecompress;
283 CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION);
284
285 Status = GetInfoFunction (
286 CompressedBuffer,
287 CompressedLength,
288 &DstSize,
289 &ScratchSize
290 );
291 if (EFI_ERROR (Status)) {
292 Error (NULL, 0, 0003, "error getting compression info from compression section", NULL);
293 return EFI_ABORTED;
294 }
295
296 if (DstSize != UncompressedLength) {
297 Error (NULL, 0, 0003, "compression error in the compression section", NULL);
298 return EFI_ABORTED;
299 }
300
301 ScratchBuffer = malloc (ScratchSize);
302 if (ScratchBuffer == NULL) {
303 return EFI_ABORTED;
304 }
305 UncompressedBuffer = malloc (UncompressedLength);
306 if (UncompressedBuffer == NULL) {
307 free (ScratchBuffer);
308 return EFI_ABORTED;
309 }
310 memset (UncompressedBuffer, 0, UncompressedLength);
311
312 Status = DecompressFunction (
313 CompressedBuffer,
314 CompressedLength,
315 UncompressedBuffer,
316 UncompressedLength,
317 ScratchBuffer,
318 ScratchSize
319 );
320 free (ScratchBuffer);
321 if (Status != EFI_SUCCESS) {
322 Error (NULL, 0, 0003, "decompress failed", NULL);
323 free (UncompressedBuffer);
324 return EFI_ABORTED;
325 }
326 } else {
327 Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType);
328 return EFI_ABORTED;
329 }
330
331 Status = ParseSection (FALSE, UncompressedBuffer, UncompressedLength, EfiBufferHeader);
332 if (Status != EFI_SUCCESS) {
333 Error (NULL, 0, 0003, "failed to parse section", NULL);
334 free (UncompressedBuffer);
335 UncompressedBuffer = NULL;
336 } else {
337 return EFI_SUCCESS;
338 }
339 //
340 // Store the allocate memory address for UncompressedBuffer
341 //
342 if (UncompressedBuffer != NULL) {
343 (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompressIndex] = (UINTN) UncompressedBuffer;
344 (*EfiBufferHeader)->UnCompressIndex = (*EfiBufferHeader)->UnCompressIndex + 1;
345 }
346 break;
347
348 case EFI_SECTION_GUID_DEFINED:
349 //
350 // Decompress failed, and then check for CRC32 sections which we can handle internally if needed.
351 // Maybe this section is no-compressed.
352 //
353 if (!CompareGuid (
354 &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid,
355 &gEfiCrc32GuidedSectionExtractionProtocolGuid
356 )) {
357 //
358 // CRC32 guided section
359 //
360 Status = ParseSection (
361 FALSE,
362 SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
363 BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
364 EfiBufferHeader
365 );
366 if (EFI_ERROR (Status)) {
367 Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL);
368 return EFI_ABORTED;
369 } else {
370 return EFI_SUCCESS;
371 }
372 } else {
373 ExtractionTool = LookupGuidedSectionToolPath (
374 mParsedGuidedSectionTools,
375 &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid
376 );
377
378 if (ExtractionTool != NULL) {
379 ToolInputFile = GenTempFile ();
380 ToolOutputFile = GenTempFile ();
381 //
382 // Construction 'system' command string
383 //
384 SystemCommandFormatString = "%s -d -o \"%s\" \"%s\"";
385 SystemCommand = malloc (
386 strlen (SystemCommandFormatString) \
387 + strlen (ExtractionTool) \
388 + strlen (ToolInputFile) \
389 + strlen (ToolOutputFile) \
390 + 1
391 );
392 if (SystemCommand == NULL) {
393 free (ExtractionTool);
394 free (ToolInputFile);
395 free (ToolOutputFile);
396 return EFI_ABORTED;
397 }
398 sprintf (
399 SystemCommand,
400 "%s -d -o \"%s\" \"%s\"",
401 ExtractionTool,
402 ToolOutputFile,
403 ToolInputFile
404 );
405 free (ExtractionTool);
406
407 Status = PutFileImage (
408 ToolInputFile,
409 (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset,
410 SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset
411 );
412
413 if (HasDepexSection) {
414 HasDepexSection = FALSE;
415 }
416
417 system (SystemCommand);
418 remove (ToolInputFile);
419 free (ToolInputFile);
420 ToolInputFile = NULL;
421 free (SystemCommand);
422 SystemCommand = NULL;
423
424 if (EFI_ERROR (Status)) {
425 Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NULL);
426 free (ToolOutputFile);
427 return EFI_ABORTED;
428 }
429
430 Status = GetFileImage (
431 ToolOutputFile,
432 (CHAR8 **)&ToolOutputBuffer,
433 &ToolOutputLength
434 );
435 remove (ToolOutputFile);
436 free (ToolOutputFile);
437 ToolOutputFile = NULL;
438 if (EFI_ERROR (Status)) {
439 return EFI_ABORTED;
440 }
441 }
442 Status = ParseSection (
443 FALSE,
444 ToolOutputBuffer,
445 ToolOutputLength,
446 EfiBufferHeader
447 );
448 if (EFI_ERROR (Status)) {
449 Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL);
450 return EFI_ABORTED;
451 }
452 }
453 break;
454
455 default:
456 ;
457 }
458 ParsedLength += SectionLength;
459 //
460 // We make then next section begin on a 4-byte boundary
461 //
462 ParsedLength = GetOccupiedSize (ParsedLength, 4);
463 }
464
465 return EFI_ABORTED;
466 }
467
468 static
469 BOOLEAN
470 GetNextOffset (
471 IN UINT8 *Data,
472 IN EFI_GUID *Guid,
473 IN UINTN Len,
474 IN OUT UINTN *Offset
475 )
476 {
477 UINTN NextOffset;
478 if (*Offset >= Len || Len - *Offset <= sizeof (EFI_GUID)) {
479 return FALSE;
480 }
481
482 for (NextOffset = *Offset; NextOffset < Len - sizeof (EFI_GUID); NextOffset++) {
483 if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) == 0) {
484 *Offset = NextOffset + sizeof(EFI_GUID);
485 return TRUE;
486 }
487 }
488 return FALSE;
489 }
490
491 /**
492 Get the address by Guid.
493
494 Parse the FFS image, and find the GUID address.There may be some Guids matching the
495 searched Guid.
496
497 @param Fv the Pointer to the image.
498 @param Guid The Guid need to find.
499 @param Offset The dual Pointer to the offset.
500 @param NumOfMatchGuid The number of matching Guid offset.
501
502 @retval EFI_SUCCESS The Search was complete successfully
503 @return EFI_ABORTED An error occurred
504 **/
505 EFI_STATUS
506 GetAddressByGuid (
507 IN VOID *Fv,
508 IN EFI_GUID *Guid,
509 IN UINTN Len,
510 OUT UINTN **Offset,
511 OUT UINT8 *NumOfMatchGuid
512 )
513 {
514 VOID *LocalFv;
515 UINT8 Flag;
516
517 EFI_RAW_SECTION* Section;
518 UINT8 *RawData;
519 VOID* SectionStart;
520 UINTN NextOffset;
521 UINTN Key;
522 UINTN TotalSectionsSize;
523 UINTN SecLen;
524 UINTN SecHdr;
525 EFI_STATUS Status;
526
527 if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) || Len == 0 ){
528 return EFI_ABORTED;
529 }
530
531 LocalFv = Fv;
532 Flag = 0;
533 Section = NULL;
534 Key = 0;
535
536 if (NumOfMatchGuid != NULL) {
537 *NumOfMatchGuid = 0;
538 }
539
540 SectionStart = (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv));
541 TotalSectionsSize = Len - FvBufGetFfsHeaderSize(LocalFv);
542 while (TRUE) {
543 Status = FvBufFindNextSection (
544 SectionStart,
545 TotalSectionsSize,
546 &Key,
547 (VOID **)&Section
548 );
549 if (Section == NULL || EFI_ERROR (Status)) {
550 break;
551 }
552
553 if (EFI_SECTION_RAW == Section->Type) {
554 if ((*(UINT32 *)Section->Size & 0xffffff) == 0xffffff) {
555 SecLen = ((EFI_RAW_SECTION2 *)Section)->ExtendedSize;
556 SecHdr = sizeof(EFI_RAW_SECTION2);
557 } else {
558 SecLen = *(UINT32 *)Section->Size & 0xffffff;
559 SecHdr = sizeof(EFI_RAW_SECTION);
560 }
561 if (SecLen <= SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) {
562 continue;
563 }
564 RawData = (UINT8 *)Section + SecHdr;
565 NextOffset = 0;
566 while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) {
567 Flag = 1;
568 if ((NumOfMatchGuid != NULL) && (Offset != NULL)) {
569 if (*NumOfMatchGuid == 0) {
570 *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
571 if (*Offset == NULL) {
572 return EFI_ABORTED;
573 }
574 memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
575 }
576 *(*Offset + *NumOfMatchGuid) = NextOffset + (RawData - (UINT8 *)Fv);
577 (*NumOfMatchGuid)++;
578 } else {
579 return EFI_SUCCESS;
580 }
581 }
582 }
583 }
584
585 if( Flag == 0 ) {
586 return EFI_ABORTED;
587 }
588 return EFI_SUCCESS;
589 }
590
591 /**
592 Search the VfrBin Base address.
593
594 According the known GUID gVfrArrayAttractGuid to get the base address from FFS.
595
596 @param Fv the Pointer to the FFS
597 @param EfiAddr the Pointer to the EFI in FFS
598 @param Length the length of Fv
599 @param Offset the Pointer to the Addr (Offset)
600 @param NumOfMachingOffset the number of Addr (Offset)
601
602 @retval EFI_SUCCESS Get the address successfully.
603 **/
604 EFI_STATUS
605 SearchVfrBinInFFS (
606 IN VOID *Fv,
607 IN VOID *EfiAddr,
608 IN UINTN Length,
609 OUT UINTN **Offset,
610 OUT UINT8 *NumOfMachingOffset
611 )
612 {
613 UINTN Index;
614 EFI_STATUS Status;
615 UINTN VirOffValue;
616
617 Index = 0;
618 Status = EFI_SUCCESS;
619 VirOffValue = 0;
620
621 if ((Fv == NULL) || (Offset == NULL)) {
622 return EFI_ABORTED;
623 }
624 Status = GetAddressByGuid (
625 Fv,
626 &gVfrArrayAttractGuid,
627 Length,
628 Offset,
629 NumOfMachingOffset
630 );
631 if (Status != EFI_SUCCESS) {
632 return EFI_ABORTED;
633 }
634
635 while (Index < *NumOfMachingOffset) {
636 //
637 // Got the virOffset after the GUID
638 //
639 VirOffValue = *(UINTN *)((UINTN)Fv + *(*Offset + Index));
640 //
641 //Transfer the offset to the VA address. One modules may own more VfrBin address.
642 //
643 *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue;
644 Index++;
645 }
646 return EFI_SUCCESS;
647 }
648
649 /**
650 Search the UniBin Base address.
651
652 According the known GUID gUniStrArrayAttractGuid to get the base address from FFS.
653
654 @param Fv the Pointer to the FFS
655 @param EfiAddr the Pointer to the EFI in FFS
656 @param Length the length of Fv
657 @param Offset the Pointer to the Addr (Offset)
658
659 @retval Base address Get the address successfully.
660 **/
661 EFI_STATUS
662 SearchUniBinInFFS (
663 IN VOID *Fv,
664 IN VOID *EfiAddr,
665 IN UINTN Length,
666 OUT UINTN **Offset
667 )
668 {
669 UINT8 NumOfMachingOffset;
670 EFI_STATUS Status;
671 UINTN VirOffValue;
672
673 NumOfMachingOffset = 0;
674 Status = EFI_SUCCESS;
675 VirOffValue = 0;
676
677 if ((Fv == NULL) || (Offset == NULL)) {
678 return EFI_ABORTED;
679 }
680 Status = GetAddressByGuid (
681 Fv,
682 &gUniStrArrayAttractGuid,
683 Length,
684 Offset,
685 &NumOfMachingOffset
686 );
687 if (Status != EFI_SUCCESS) {
688 return EFI_ABORTED;
689 }
690 //
691 //Transfer the offset to the VA address. There is only one UniArray in one modules.
692 //
693 if (NumOfMachingOffset == 1) {
694 VirOffValue = *(UINTN *)((UINTN)Fv + **Offset);
695 **Offset = (UINTN) EfiAddr + VirOffValue;
696 } else {
697 printf ("Error. Find more than 1 UniBin in FFS.\n");
698 return EFI_ABORTED;
699 }
700
701 return EFI_SUCCESS;
702 }
703
704 EFI_STATUS
705 SearchNvStoreDatabaseInFd(
706 IN VOID *Fv,
707 IN UINTN length
708 )
709 {
710 EFI_STATUS Status;
711 UINTN Offset;
712 PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader;
713 Status = EFI_SUCCESS;
714 Offset = 0;
715 if (Fv == NULL) {
716 printf ("The FV is NULL.");
717 return EFI_ABORTED;
718 }
719 while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){
720 NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + Offset);
721 if (NvStoreHeader->Signature == PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE) {
722 gEfiFdInfo.ExistNvStoreDatabase = TRUE;
723 gEfiFdInfo.NvStoreDatabase = (UINT8 *) NvStoreHeader;
724 break;
725 }
726 Offset++;
727 }
728 if (Offset == (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) || gEfiFdInfo.ExistNvStoreDatabase != TRUE) {
729 //printf ("Not found the PcdNvStoreDefaultValueBuffer\n");
730 return Status;
731 }
732 return Status;
733 }
734
735 /**
736 Get the address by Guid.
737
738 Parse the FD image, and find the GUID address.There may be some Guids matching the
739 searched Guid.
740
741 @param Fv the Pointer to the image.
742 @param Guid The Guid need to find.
743 @param Offset The dual Pointer to the offset.
744 @param NumOfMatchGuid The number of matching Guid offset.
745
746 @retval EFI_SUCCESS The Search was complete successfully
747 @return EFI_ABORTED An error occurred
748 **/
749 EFI_STATUS
750 GetVariableAddressByGuid (
751 IN VOID *Fv,
752 IN EFI_GUID *Guid,
753 IN UINTN Len,
754 OUT UINTN **Offset,
755 OUT UINT8 *NumOfMatchGuid
756 )
757 {
758 UINTN NextOffset;
759 UINT8 Flag;
760
761 if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) ){
762 return EFI_ABORTED;
763 }
764
765 Flag = 0;
766 NextOffset = 0;
767
768 if (NumOfMatchGuid != NULL) {
769 *NumOfMatchGuid = 0;
770 }
771 while (GetNextOffset(Fv, Guid, Len, &NextOffset)) {
772 Flag = 1;
773 if (NumOfMatchGuid != NULL && Offset != NULL) {
774 if (*NumOfMatchGuid == 0) {
775 *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM);
776 if (*Offset == NULL) {
777 return EFI_ABORTED;
778 }
779 memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM);
780 }
781 *(*Offset + *NumOfMatchGuid) = NextOffset;
782 (*NumOfMatchGuid)++;
783 } else {
784 return EFI_SUCCESS;
785 }
786 }
787
788 if( Flag == 0 ) {
789 return EFI_ABORTED;
790 }
791 return EFI_SUCCESS;
792 }
793
794 /**
795 Search the EFI Variable Base address.
796
797 According the known GUID gEfiSystemNvDataFvGuid to get the base address from FFS.
798
799 @param Fv the Pointer to the FFS
800 @param Length the length of Fv
801 @param Offset the Pointer to the Addr (Offset)
802 @param NumOfMachingOffset the number of IFR array in one FFS
803
804 @retval EFI_SUCCESS Get the address successfully.
805 @retval EFI_ABORTED An error occured.
806 **/
807 EFI_STATUS
808 SearchEfiVarInFFS (
809 IN VOID *Fv,
810 IN UINTN Length,
811 OUT UINTN **Offset,
812 OUT UINT8 *NumOfMachingOffset
813 )
814 {
815 EFI_STATUS Status;
816 UINT8 Index;
817
818 Status = EFI_SUCCESS;
819 Index = 0;
820
821 if ((Fv == NULL) || (Offset == NULL)) {
822 printf ("The FV or offset is NULL.");
823 return EFI_ABORTED;
824 }
825 Status = GetVariableAddressByGuid (
826 Fv,
827 &gEfiSystemNvDataFvGuid,
828 Length,
829 Offset,
830 NumOfMachingOffset
831 );
832 if (Status != EFI_SUCCESS) {
833 return EFI_ABORTED;
834 }
835 //
836 //Transfer the offset to the VA address.
837 //
838 while (Index < *NumOfMachingOffset) {
839 *(*Offset + Index) = (UINTN) Fv + *(*Offset + Index);
840 Index++;
841 }
842 return EFI_SUCCESS;
843 }
844
845 /**
846 Parse the Ffs header to get the size.
847
848 @param InputFile The pointer to the input file
849 @param FvSize The pointer to the file size
850
851 @return EFI_SUCCESS Get the file size successfully
852 **/
853 EFI_STATUS
854 ReadFfsHeader (
855 IN FILE *InputFile,
856 OUT UINT32 *FvSize
857 )
858 {
859 EFI_FFS_FILE_HEADER FfsHeader;
860 EFI_FV_FILETYPE Type;
861
862 //
863 // Check input parameters
864 //
865 if ((InputFile == NULL) || (FvSize == NULL)) {
866 return EFI_ABORTED;
867 }
868 //
869 // Read the header
870 //
871 fread (
872 &FfsHeader,
873 sizeof (EFI_FFS_FILE_HEADER),
874 1,
875 InputFile
876 );
877 Type = FfsHeader.Type;
878
879 if (Type == EFI_FV_FILETYPE_DRIVER) {
880 *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
881 } else if (Type == EFI_FV_FILETYPE_APPLICATION) {
882 *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
883 } else if (Type == EFI_FV_FILETYPE_FREEFORM) {
884 *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff;
885 } else {
886 return EFI_ABORTED;
887 }
888 return EFI_SUCCESS;
889 }
890
891 /*
892 Read the length of the whole FD
893
894 This function determines the size of the FV.
895
896 @param InputFile The file that contains the FV image.
897 @param FvSize The size of the FV.
898
899 @retval EFI_SUCCESS The application exited normally.
900 @retval EFI_ABORTED An error occurred.
901
902 **/
903 static
904 EFI_STATUS
905 ReadFdHeader (
906 IN FILE *InputFile,
907 OUT UINT32 *FvSize
908 )
909 {
910 //
911 // Check input parameters
912 //
913 if ((InputFile == NULL) || (FvSize == NULL)) {
914 return EFI_ABORTED;
915 }
916 *FvSize = 0;
917 //
918 // Get the total size of FD file (Fixed the length)
919 //
920 fseek(InputFile,0,SEEK_END);
921 *FvSize = ftell(InputFile);
922 fseek(InputFile,0,SEEK_SET);
923
924 if (*FvSize == 0) {
925 return EFI_ABORTED;
926 }
927 return EFI_SUCCESS;
928 }
929
930 /**
931 Read the file to memory.
932
933 @param InputFile The file that contains the FV image.
934 @param Size The size of the file.
935
936 @retval The pointer to the begining position of memory.
937 **/
938 VOID *
939 ReadFileToMemory (
940 IN CHAR8 *FileName,
941 OUT UINT32 *Size
942 )
943 {
944 FILE *InFile;
945 VOID *Address;
946 UINT32 BytesRead;
947 EFI_STATUS Status;
948
949 InFile = NULL;
950 Address = NULL;
951 BytesRead = 0;
952 Status = EFI_SUCCESS;
953
954 InFile = fopen (FileName,"rb");
955 if (InFile == NULL) {
956 return NULL;
957 }
958 //
959 // Determine the size of FV
960 //
961 Status = ReadFdHeader (InFile, Size);
962 if (Status != EFI_SUCCESS) {
963 fclose (InFile);
964 return NULL;
965 }
966 //
967 // Allocate a buffer for the FV image
968 //
969 Address = malloc (*Size);
970 if (Address == NULL) {
971 fclose (InFile);
972 return NULL;
973 }
974 memset (Address, 0, *Size);
975 //
976 // Seek to the start of the image, then read the entire FV to the buffer
977 //
978 fseek (InFile, 0, SEEK_SET);
979 BytesRead = fread (Address, 1, *Size, InFile);
980 fclose (InFile);
981 if ((UINTN) BytesRead != *Size) {
982 free (Address);
983 return NULL;
984 }
985 return Address;
986 }
987
988 /**
989 Search the EFI variables address in Fd.
990
991 Open and read the *.fd to the memory, initialize the global structure.
992 Update the EFI variables addr and the begining position of memory.
993
994 @retval EFI_SUCCESS Get the address successfully.
995 **/
996 EFI_STATUS
997 GetEfiVariablesAddr (
998 BOOLEAN UqiIsSet
999 )
1000 {
1001 VOID *FdImage;
1002 UINT32 FdSize;
1003 EFI_STATUS Status;
1004 UINTN *EfiVarAddr;
1005 UINT8 NumOfMachingVar;
1006 UINT32 Index;
1007 BOOLEAN GotFlag;
1008 EFI_FIRMWARE_VOLUME_HEADER *Variable;
1009 BOOLEAN AuthencitatedMonotonicOrNot;
1010 BOOLEAN AuthencitatedBasedTimeOrNot;
1011 BOOLEAN NormalOrNot;
1012
1013 FdImage = NULL;
1014 FdSize = 0;
1015 Status = EFI_SUCCESS;
1016 EfiVarAddr = NULL;
1017 NumOfMachingVar = 0;
1018 Index = 0;
1019 GotFlag = TRUE;
1020 Variable = NULL;
1021
1022 FdImage = ReadFileToMemory (mInputFdName, &FdSize);
1023 if (FdImage == NULL) {
1024 return EFI_ABORTED;
1025 }
1026 if (!UqiIsSet) {
1027 Status = SearchNvStoreDatabaseInFd(FdImage, FdSize);
1028 if (EFI_ERROR (Status)) {
1029 return EFI_ABORTED;
1030 }
1031 }
1032 Status = SearchEfiVarInFFS (
1033 FdImage,
1034 FdSize,
1035 &EfiVarAddr,
1036 &NumOfMachingVar
1037 );
1038 if (EFI_ERROR (Status)) {
1039 return EFI_ABORTED;
1040 }
1041 //
1042 // Check the signature "_FVH"
1043 //
1044 Index = 0;
1045 GotFlag = FALSE;
1046
1047 while (Index < NumOfMachingVar) {
1048 Variable = (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x20);
1049 if (Variable->Signature == 0x4856465F) {
1050 AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((UINT8 *)Variable + Variable->HeaderLength);
1051 AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
1052 NormalOrNot = CheckNormalVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength);
1053 if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || NormalOrNot) {
1054 GotFlag = TRUE;
1055 gEfiFdInfo.EfiVariableAddr = (UINTN)Variable;
1056 break;
1057 }
1058 }
1059 Index++;
1060 }
1061 free (EfiVarAddr);
1062 if (!GotFlag) {
1063 return EFI_ABORTED;
1064 }
1065 gEfiFdInfo.Fd = FdImage;
1066 gEfiFdInfo.FdSize = FdSize;
1067
1068 return EFI_SUCCESS;
1069 }
1070
1071 /**
1072 Pick up the FFS which includes IFR section.
1073
1074 Parse all FFS extracted by BfmLib, and save all which includes IFR
1075 Binary to gEfiFdInfo structure.
1076
1077 @retval EFI_SUCCESS Get the address successfully.
1078 @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated.
1079 @retval EFI_ABORTED Read FFS Failed.
1080 **/
1081 EFI_STATUS
1082 FindFileInFolder (
1083 IN CHAR8 *FolderName,
1084 OUT BOOLEAN *ExistStorageInBfv,
1085 OUT BOOLEAN *SizeOptimized
1086 )
1087 {
1088 CHAR8 *FileName;
1089 CHAR8 *CurFolderName;
1090 EFI_STATUS Status;
1091 UINTN MaxFileNameLen;
1092 UINTN Index;
1093 CHAR8 FileNameArry[MAX_FILENAME_LEN];
1094 FILE *FfsFile;
1095 UINTN FileSize;
1096 VOID *FfsImage;
1097 UINTN BytesRead;
1098 #ifndef __GNUC__
1099 HANDLE FindHandle;
1100 WIN32_FIND_DATA FindFileData;
1101 #else
1102 struct dirent *pDirent;
1103 DIR *pDir;
1104 #endif
1105
1106 FileName = NULL;
1107 CurFolderName = NULL;
1108 Status = EFI_SUCCESS;
1109 MaxFileNameLen = 0;
1110 Index = 0;
1111 FileSize = 0;
1112 BytesRead = 0;
1113 FfsImage = NULL;
1114 FfsFile = NULL;
1115
1116 MaxFileNameLen = strlen (FolderName) + MAX_FILENAME_LEN;
1117 CurFolderName = (CHAR8 *)calloc(
1118 strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("*.*")+ 1,
1119 sizeof(CHAR8)
1120 );
1121 if (CurFolderName == NULL) {
1122 return EFI_BUFFER_TOO_SMALL;
1123 }
1124 strcpy (CurFolderName, FolderName);
1125 strcat (CurFolderName, OS_SEP_STR);
1126 strcat (CurFolderName, "*.*");
1127 FileName = (CHAR8 *)calloc(
1128 MaxFileNameLen,
1129 sizeof(CHAR8)
1130 );
1131 if (FileName == NULL) {
1132 free (CurFolderName);
1133 return EFI_BUFFER_TOO_SMALL;
1134 }
1135
1136 #ifndef __GNUC__
1137 if((FindHandle = FindFirstFile(CurFolderName, &FindFileData)) != INVALID_HANDLE_VALUE){
1138 do {
1139 memset (FileName, 0, MaxFileNameLen);
1140 if ((strcmp (FindFileData.cFileName, ".") == 0)
1141 || (strcmp (FindFileData.cFileName, "..") == 0)
1142 ) {
1143 continue;
1144 }
1145 if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileName) > MAX_FILENAME_LEN - 1) {
1146 Status = EFI_ABORTED;
1147 goto Done;
1148 }
1149 snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_SEP, FindFileData.cFileName);
1150 FfsFile = fopen (FileNameArry, "rb");
1151 if (FfsFile == NULL) {
1152 Status = EFI_ABORTED;
1153 goto Done;
1154 }
1155 Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
1156 if (EFI_ERROR (Status)) {
1157 fclose (FfsFile);
1158 Status = EFI_SUCCESS;
1159 continue;
1160 }
1161 //
1162 // Allocate a buffer for the FFS file
1163 //
1164 FfsImage = malloc (FileSize);
1165 if (FfsImage == NULL) {
1166 fclose (FfsFile);
1167 Status = EFI_BUFFER_TOO_SMALL;
1168 goto Done;
1169 }
1170 //
1171 // Seek to the start of the image, then read the entire FV to the buffer
1172 //
1173 fseek (FfsFile, 0, SEEK_SET);
1174 BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
1175 fclose (FfsFile);
1176
1177 if ((UINTN) BytesRead != FileSize) {
1178 free (FfsImage);
1179 Status = EFI_ABORTED;
1180 goto Done;
1181 }
1182 //
1183 // Check whether exists the storage ffs in BFV for multi-platform mode
1184 //
1185 if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
1186 *ExistStorageInBfv = TRUE;
1187 *SizeOptimized = FALSE;
1188 gEfiFdInfo.StorageFfsInBfv = FfsImage;
1189 continue;
1190 }
1191 //
1192 // Check whether exists the optimized storage ffs in BFV for multi-platform mode
1193 //
1194 if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
1195 *ExistStorageInBfv = TRUE;
1196 *SizeOptimized = TRUE;
1197 gEfiFdInfo.StorageFfsInBfv = FfsImage;
1198 continue;
1199 }
1200 //
1201 // Check whether current FFS includes IFR
1202 //
1203 Status = GetAddressByGuid (
1204 FfsImage,
1205 &gVfrArrayAttractGuid,
1206 FileSize,
1207 NULL,
1208 NULL
1209 );
1210 if (EFI_ERROR (Status)) {
1211 free (FfsImage);
1212 Status = EFI_SUCCESS;
1213 } else {
1214 //
1215 // Check whether existed same IFR binary. If existed, not insert the new one.
1216 //
1217 if (NotExistSameFfsIfr (FfsImage)) {
1218 gEfiFdInfo.FfsArray[Index] = FfsImage;
1219 gEfiFdInfo.Length[Index++] = FileSize;
1220 }
1221 }
1222
1223 } while (FindNextFile (FindHandle, &FindFileData));
1224 FindClose(FindHandle);
1225 } else {
1226 Status = EFI_ABORTED;
1227 goto Done;
1228 }
1229
1230 Done:
1231 free (CurFolderName);
1232 free (FileName);
1233
1234 #else
1235 if((pDir = opendir(FolderName)) != NULL){
1236 while ((pDirent = readdir(pDir)) != NULL){
1237 memset (FileName, 0, MaxFileNameLen);
1238 if ((strcmp (pDirent->d_name, ".") == 0)
1239 || (strcmp (pDirent->d_name, "..") == 0)
1240 ) {
1241 continue;
1242 }
1243 sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name);
1244 FfsFile = fopen (FileNameArry, "rb");
1245 Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize);
1246 if (EFI_ERROR (Status)) {
1247 fclose (FfsFile);
1248 Status = EFI_SUCCESS;
1249 continue;
1250 }
1251 //
1252 // Allocate a buffer for the FFS file
1253 //
1254 FfsImage = malloc (FileSize);
1255 if (FfsImage == NULL) {
1256 fclose (FfsFile);
1257 Status = EFI_BUFFER_TOO_SMALL;
1258 goto Done;
1259 }
1260 //
1261 // Seek to the start of the image, then read the entire FV to the buffer
1262 //
1263 fseek (FfsFile, 0, SEEK_SET);
1264 BytesRead = fread (FfsImage, 1, FileSize, FfsFile);
1265 fclose (FfsFile);
1266
1267 if ((UINTN) BytesRead != FileSize) {
1268 free (FfsImage);
1269 Status = EFI_ABORTED;
1270 goto Done;
1271 }
1272 //
1273 // Check whether exists the storage ffs in BFV for multi-platform mode
1274 //
1275 if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) {
1276 *ExistStorageInBfv = TRUE;
1277 *SizeOptimized = FALSE;
1278 gEfiFdInfo.StorageFfsInBfv = FfsImage;
1279 continue;
1280 }
1281 //
1282 // Check whether exists the optimized storage ffs in BFV for multi-platform mode
1283 //
1284 if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) {
1285 *ExistStorageInBfv = TRUE;
1286 *SizeOptimized = TRUE;
1287 gEfiFdInfo.StorageFfsInBfv = FfsImage;
1288 continue;
1289 }
1290 //
1291 // Check whether current FFS includes IFR
1292 //
1293 Status = GetAddressByGuid (
1294 FfsImage,
1295 &gVfrArrayAttractGuid,
1296 FileSize,
1297 NULL,
1298 NULL
1299 );
1300 if (EFI_ERROR (Status)) {
1301 free (FfsImage);
1302 Status = EFI_SUCCESS;
1303 } else {
1304 //
1305 // Check whether existed same IFR binary. If existed, not insert the new one.
1306 //
1307 if (NotExistSameFfsIfr (FfsImage)) {
1308 gEfiFdInfo.FfsArray[Index] = FfsImage;
1309 gEfiFdInfo.Length[Index++] = FileSize;
1310 }
1311 }
1312
1313 }
1314 closedir(pDir);
1315 } else {
1316 Status = EFI_ABORTED;
1317 goto Done;
1318 }
1319
1320 Done:
1321 free (CurFolderName);
1322 free (FileName);
1323 #endif
1324 return Status;
1325 }
1326