]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/BfmLib/BinFileManager.c
BaseTools/BfmLib: Add a tool BfmLib
[mirror_edk2.git] / BaseTools / Source / C / BfmLib / BinFileManager.c
1 /** @file
2
3 The main entry of BFM tool.
4
5 Copyright (c) 2011-2019, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "BinFileManager.h"
11
12 BOOLEAN mFvGuidIsSet = FALSE;
13 EFI_GUID mFvNameGuid = {0};
14 CHAR8* mFvNameGuidString = NULL;
15 CHAR8* mGuidToolDefinition = "GuidToolDefinitionConf.ini";
16
17 //
18 // Store GUIDed Section guid->tool mapping
19 //
20 EFI_HANDLE mParsedGuidedSectionTools = NULL;
21
22
23 /**
24 Search the config file from the path list.
25
26 Split the path from env PATH, and then search the cofig
27 file from these paths. The priority is from left to
28 right of PATH string. When met the first Config file, it
29 will break and return the pointer to the full file name.
30
31 @param PathList the pointer to the path list.
32 @param FileName the pointer to the file name.
33
34 @retval The pointer to the file name.
35 @return NULL An error occurred.
36 **/
37 CHAR8 *
38 SearchConfigFromPathList (
39 IN CHAR8 *PathList,
40 IN CHAR8 *FileName
41 )
42 {
43 CHAR8 *CurDir;
44 CHAR8 *FileNamePath;
45
46 CurDir = NULL;
47 FileNamePath = NULL;
48 #ifndef __GNUC__
49 CurDir = strtok (PathList,";");
50 #else
51 CurDir = strtok (PathList,":");
52 #endif
53 while (CurDir != NULL) {
54 FileNamePath = (char *)calloc(
55 strlen (CurDir) + strlen (OS_SEP_STR) +strlen (FileName) + 1,
56 sizeof(char)
57 );
58 if (FileNamePath == NULL) {
59 return NULL;
60 }
61 sprintf(FileNamePath, "%s%c%s", CurDir, OS_SEP, FileName);
62 if (access (FileNamePath, 0) != -1) {
63 return FileNamePath;
64 }
65 #ifndef __GNUC__
66 CurDir = strtok(NULL, ";");
67 #else
68 CurDir = strtok(NULL, ":");
69 #endif
70 free (FileNamePath);
71 FileNamePath = NULL;
72 }
73 return NULL;
74 }
75
76 /**
77
78 Show the FD image layout information. Only display the modules with UI name.
79
80 @param[in] FdInName Input FD binary/image file name;
81 @param[in] FvName The FV ID in the FD file;
82 @param[in] ViewFlag Is this call for view or other operate(add/del/replace)
83 @param[in] FdData The Fd data structure store the FD information.
84
85 @retval EFI_SUCCESS
86 @retval EFI_INVALID_PARAMETER
87 @retval EFI_ABORTED
88
89 **/
90 EFI_STATUS
91 BfmImageView (
92 IN CHAR8* FdInName,
93 IN CHAR8* FvName,
94 IN BOOLEAN ViewFlag,
95 IN FIRMWARE_DEVICE **FdData
96 )
97 {
98 EFI_STATUS Status;
99 FIRMWARE_DEVICE *LocalFdData;
100 FV_INFORMATION *CurrentFv;
101 FILE *InputFile;
102 UINT32 FvSize;
103 UINTN BytesRead;
104 EFI_FIRMWARE_VOLUME_HEADER *FvImage;
105 UINT32 FfsCount;
106 UINT8 FvCount;
107 UINT8 LastFvNumber;
108
109 LocalFdData = NULL;
110 CurrentFv = NULL;
111 FvImage = NULL;
112 FvSize = 0;
113 BytesRead = 0;
114 FfsCount = 0;
115 FvCount = 0;
116 LastFvNumber = 0;
117
118 //
119 // Check the FD file name/path.
120 //
121 if (FdInName == NULL) {
122 return EFI_INVALID_PARAMETER;
123 }
124
125 //
126 // Open the file containing the FV
127 //
128 InputFile = fopen (FdInName, "rb");
129 if (InputFile == NULL) {
130 return EFI_INVALID_PARAMETER;
131 }
132
133 Status = LibFindFvInFd (InputFile, &LocalFdData);
134
135 if (EFI_ERROR(Status)) {
136 fclose (InputFile);
137 return EFI_ABORTED;
138 }
139
140 CurrentFv = LocalFdData->Fv;
141
142 do {
143
144 memset (CurrentFv->FvName, '\0', _MAX_PATH);
145
146 if (LastFvNumber == 0) {
147 sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
148 } else {
149 sprintf (CurrentFv->FvName, "FV%d", LastFvNumber);
150 }
151
152 //
153 // Determine size of FV
154 //
155 if (fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET) != 0) {
156 fclose (InputFile);
157 LibBfmFreeFd( LocalFdData);
158 return EFI_ABORTED;
159 }
160
161 Status = LibGetFvSize(InputFile, &FvSize);
162 if (EFI_ERROR (Status)) {
163 fclose (InputFile);
164 return EFI_ABORTED;
165 }
166
167 //
168 // Seek to the start of the image, then read the entire FV to the buffer
169 //
170 fseek (InputFile, CurrentFv->ImageAddress, SEEK_SET);
171
172 FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) malloc (FvSize);
173
174 if (FvImage == NULL) {
175 fclose (InputFile);
176 LibBfmFreeFd( LocalFdData);
177 return EFI_ABORTED;
178 }
179
180 BytesRead = fread (FvImage, 1, FvSize, InputFile);
181 if ((unsigned int) BytesRead != FvSize) {
182 free (FvImage);
183 fclose (InputFile);
184 LibBfmFreeFd( LocalFdData);
185 return EFI_ABORTED;
186 }
187
188 //
189 // Collect FV information each by each.
190 //
191 Status = LibGetFvInfo (FvImage, CurrentFv, FvName, 0, &FfsCount, ViewFlag, FALSE);
192 free (FvImage);
193 FvImage = NULL;
194 if (EFI_ERROR (Status)) {
195 fclose (InputFile);
196 LibBfmFreeFd( LocalFdData);
197 return Status;
198 }
199 FvCount = CurrentFv->FvLevel;
200 LastFvNumber = LastFvNumber+FvCount;
201
202 FfsCount = 0;
203
204 CurrentFv = CurrentFv->FvNext;
205
206 } while (CurrentFv != NULL);
207
208 if (!ViewFlag) {
209 *FdData = LocalFdData;
210 } else {
211 LibBfmFreeFd( LocalFdData);
212 }
213
214 fclose (InputFile);
215
216 return EFI_SUCCESS;
217 }
218
219 /**
220 Add an FFS file into a specify FV.
221
222 @param[in] FdInName Input FD binary/image file name;
223 @param[in] NewFile The name of the file add in;
224 @param[in] FdOutName Name of output fd file.
225
226 @retval EFI_SUCCESS
227 @retval EFI_INVALID_PARAMETER
228 @retval EFI_ABORTED
229
230 **/
231 EFI_STATUS
232 BfmImageAdd (
233 IN CHAR8* FdInName,
234 IN CHAR8* NewFile,
235 IN CHAR8* FdOutName
236 )
237 {
238 EFI_STATUS Status;
239 FIRMWARE_DEVICE *FdData;
240 FV_INFORMATION *FvInFd;
241 ENCAP_INFO_DATA *LocalEncapData;
242 ENCAP_INFO_DATA *LocalEncapDataTemp;
243 FILE* NewFdFile;
244 FILE* NewFvFile;
245 UINT64 NewFvLength;
246 UINT64 NewFfsLength;
247 VOID* Buffer;
248 CHAR8 *TemDir;
249 UINT8 FvEncapLevel;
250 UINT8 NewAddedFfsLevel;
251 BOOLEAN FfsLevelFoundFlag;
252 CHAR8 *OutputFileName;
253 CHAR8 *FvId;
254 BOOLEAN FirstInFlag;
255 BOOLEAN FvGuidExisted;
256
257 NewFvLength = 0;
258 FvEncapLevel = 0;
259 NewAddedFfsLevel = 0;
260
261 FfsLevelFoundFlag = FALSE;
262 FirstInFlag = TRUE;
263 FdData = NULL;
264 FvInFd = NULL;
265 LocalEncapData = NULL;
266 NewFdFile = NULL;
267 NewFvFile = NULL;
268 Buffer = NULL;
269 TemDir = NULL;
270 LocalEncapDataTemp = NULL;
271 OutputFileName = NULL;
272 FvId = NULL;
273 FvGuidExisted = FALSE;
274
275 //
276 // Get the size of ffs file to be inserted.
277 //
278 NewFfsLength = GetFileSize(NewFile);
279
280 Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
281
282 if (EFI_ERROR (Status)) {
283 printf ("Error while parse %s FD image.\n", FdInName);
284 return Status;
285 }
286 //
287 // Check the FvGuid whether exists or not when the BIOS hasn't default setting.
288 // If the FV image with -g GUID can't be found, the storage is still saved into the BFV and report warning message.
289 //
290 FvInFd = FdData->Fv;
291 do {
292 if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
293 FvGuidExisted = TRUE;
294 break;
295 }
296 FvInFd = FvInFd->FvNext;
297 } while (FvInFd != NULL);
298
299 if (mFvGuidIsSet && !FvGuidExisted) {
300 printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
301 LibBfmFreeFd(FdData);
302 return EFI_ABORTED;
303 }
304 //
305 // Iterate to write FFS to each BFV.
306 //
307 FvInFd = FdData->Fv;
308 do {
309 if ((FvGuidExisted && mFvGuidIsSet && FvInFd->IsInputFvFlag) || ((!FvGuidExisted || (!mFvGuidIsSet)) && FvInFd->IsBfvFlag)) {
310
311 Status = LibLocateBfv (FdData, &FvId, &FvInFd);
312
313 if (EFI_ERROR (Status)) {
314 printf("Error while locate BFV from FD.\n");
315 LibBfmFreeFd(FdData);
316 return Status;
317 }
318
319 //
320 // Determine the new added ffs file level in the FV.
321 //
322 LocalEncapData = FvInFd->EncapData;
323
324 while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
325 if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
326 if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
327 //
328 // Found the FFS level in this FV.
329 //
330 LocalEncapDataTemp = LocalEncapData;
331 while (LocalEncapDataTemp != NULL) {
332 if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
333 NewAddedFfsLevel = LocalEncapDataTemp->Level;
334 FfsLevelFoundFlag = TRUE;
335 break;
336 }
337 if (LocalEncapDataTemp->NextNode != NULL) {
338 LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
339 } else {
340 break;
341 }
342 }
343 }
344 FvEncapLevel ++;
345 }
346
347 if (LocalEncapData->NextNode == NULL) {
348 break;
349 } else {
350 LocalEncapData = LocalEncapData->NextNode;
351 }
352 }
353
354 //
355 // Add the new file into FV.
356 //
357 FvInFd->FfsNumbers += 1;
358 if (strlen (NewFile) > _MAX_PATH - 1) {
359 printf ("The NewFile name is too long \n");
360 LibBfmFreeFd(FdData);
361 return EFI_ABORTED;
362 }
363 strncpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH - 1);
364 FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName[_MAX_PATH - 1] = 0;
365 FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
366
367 TemDir = getcwd (NULL, _MAX_PATH);
368 if (strlen (TemDir) + strlen (OS_SEP_STR) + strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
369 printf ("The directory is too long \n");
370 LibBfmFreeFd(FdData);
371 return EFI_ABORTED;
372 }
373 strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
374 strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
375 mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
376 Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
377
378 if (EFI_ERROR (Status)) {
379 printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n",(unsigned long) GetBfvPadSize (), (unsigned long long)NewFfsLength);
380 LibBfmFreeFd(FdData);
381 return Status;
382 }
383
384 if (FirstInFlag) {
385 //
386 // Write New Fv file into the NewFd file.
387 //
388 Status = LibCreateNewFdCopy (FdInName, FdOutName);
389 if (EFI_ERROR (Status)) {
390 printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
391 LibBfmFreeFd(FdData);
392 return Status;
393 }
394 FirstInFlag = FALSE;
395 }
396
397 NewFdFile = fopen (FdOutName, "rb+");
398 if (NewFdFile == NULL) {
399 printf("Error while create FD file %s. \n", FdOutName);
400 LibBfmFreeFd(FdData);
401 return EFI_ABORTED;
402 }
403
404 NewFvFile = fopen (OutputFileName, "rb+");
405
406 if (NewFvFile == NULL) {
407 printf("Error while create Fv file %s. \n", OutputFileName);
408 fclose(NewFdFile);
409 LibBfmFreeFd(FdData);
410 return EFI_ABORTED;
411 }
412
413 fseek(NewFvFile,0,SEEK_SET);
414 fseek(NewFvFile,0,SEEK_END);
415
416 NewFvLength = ftell(NewFvFile);
417
418 fseek(NewFvFile,0,SEEK_SET);
419
420 Buffer = malloc ((size_t)NewFvLength);
421
422 if (Buffer == NULL) {
423 printf ("Error while allocate resource! \n");
424 fclose(NewFdFile);
425 fclose(NewFvFile);
426 LibBfmFreeFd(FdData);
427 return EFI_ABORTED;
428 }
429
430 if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
431 printf("Error while reading Fv file %s. \n", OutputFileName);
432 free (Buffer);
433 fclose(NewFdFile);
434 fclose(NewFvFile);
435 LibBfmFreeFd(FdData);
436 return EFI_ABORTED;
437 }
438
439 fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
440 fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
441
442 if (NewFvLength <= FvInFd->FvHeader->FvLength) {
443 if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
444 printf("Error while writing FD file %s. \n", FdOutName);
445 fclose(NewFdFile);
446 fclose (NewFvFile);
447 free (Buffer);
448 LibBfmFreeFd(FdData);
449 return EFI_ABORTED;
450 }
451 } else {
452 printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
453 free (Buffer);
454 fclose(NewFdFile);
455 fclose(NewFvFile);
456 LibBfmFreeFd(FdData);
457 return EFI_ABORTED;
458 }
459
460 fclose(NewFdFile);
461 fclose(NewFvFile);
462 free (Buffer);
463 Buffer = NULL;
464
465 }
466 FvInFd = FvInFd->FvNext;
467 } while (FvInFd != NULL);
468
469
470 LibBfmFreeFd(FdData);
471
472 if (TemDir == NULL) {
473 if (mFvGuidIsSet) {
474 printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
475 } else {
476 printf ("BFV image can't be found.\n");
477 }
478 return EFI_NOT_FOUND;
479 }
480
481 Status = LibRmDir (TemDir);
482
483 if (EFI_ERROR (Status)) {
484 printf("Error while remove temporary directory. \n");
485 return Status;
486 }
487
488 return EFI_SUCCESS;
489 }
490
491
492 /**
493 Replace an FFS file into a specify FV.
494
495 @param[in] FdInName Input FD binary/image file name;
496 @param[in] NewFile The name of the file add in;
497 @param[in] FdOutName Name of output fd file.
498
499 @retval EFI_SUCCESS
500 @retval EFI_INVALID_PARAMETER
501 @retval EFI_ABORTED
502
503 **/
504 EFI_STATUS
505 BfmImageReplace (
506 IN CHAR8* FdInName,
507 IN CHAR8* NewFile,
508 IN CHAR8* FdOutName
509 )
510 {
511 EFI_STATUS Status;
512 FIRMWARE_DEVICE *FdData;
513 FV_INFORMATION *FvInFd;
514 FILE* NewFdFile;
515 FILE* NewFvFile;
516 UINT64 NewFvLength;
517 UINT64 NewFfsLength;
518 VOID* Buffer;
519 CHAR8 *TemDir;
520 CHAR8 *OutputFileName;
521 CHAR8 *FvId;
522 BOOLEAN FirstInFlag;
523 UINT32 Index;
524 BOOLEAN FvToBeUpdate;
525 BOOLEAN FdIsUpdate;
526 ENCAP_INFO_DATA *LocalEncapData;
527 ENCAP_INFO_DATA *LocalEncapDataTemp;
528 UINT8 FvEncapLevel;
529 UINT8 NewAddedFfsLevel;
530 BOOLEAN FfsLevelFoundFlag;
531 EFI_GUID EfiNewAddToBfvGuid;
532 FILE* FfsFile;
533 UINTN BytesRead;
534 BOOLEAN ReplaceSameFv;
535 BOOLEAN FvGuidExisted;
536
537 NewFvLength = 0;
538 FdIsUpdate = FALSE;
539 FirstInFlag = TRUE;
540 FdData = NULL;
541 FvInFd = NULL;
542 NewFdFile = NULL;
543 NewFvFile = NULL;
544 Buffer = NULL;
545 TemDir = NULL;
546 OutputFileName = NULL;
547 FvId = NULL;
548 FfsFile = NULL;
549 BytesRead = 0;
550 ReplaceSameFv = FALSE;
551 FvGuidExisted = FALSE;
552
553 //
554 // Get the size of ffs file to be inserted.
555 //
556 NewFfsLength = GetFileSize(NewFile);
557 //
558 // Get FFS GUID
559 //
560 FfsFile = fopen (NewFile, "rb");
561 if (FfsFile == NULL) {
562 printf ("Error while read %s.\n", NewFile);
563 return EFI_ABORTED;
564 }
565 fseek (FfsFile, 0, SEEK_SET);
566 BytesRead = fread (&EfiNewAddToBfvGuid, 1, sizeof(EFI_GUID), FfsFile);
567 fclose (FfsFile);
568 if (BytesRead != sizeof(EFI_GUID)) {
569 printf ("Error while read the GUID from %s.\n", NewFile);
570 return EFI_ABORTED;
571 }
572 Status = BfmImageView (FdInName, NULL, FALSE, &FdData);
573
574 if (EFI_ERROR (Status)) {
575 printf ("Error while parse %s FD image.\n", FdInName);
576 return Status;
577 }
578
579 //
580 // Check the FvGuid whether exists or not when the BIOS has default setting.
581 // 1. No option means the storage is saved into the same FV image.
582 // 2. The FV image with -g GUID can't be found. The storage is still saved into the same FV image and report warning message.
583 //
584 if (!mFvGuidIsSet) {
585 ReplaceSameFv = TRUE;
586 }
587 FvInFd = FdData->Fv;
588 do {
589 if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
590 FvGuidExisted = TRUE;
591 break;
592 }
593 FvInFd = FvInFd->FvNext;
594 } while (FvInFd != NULL);
595
596 if (mFvGuidIsSet && !FvGuidExisted) {
597 printf ("Fv image with the specified FV Name Guid %s can't be found in current FD.\n", mFvNameGuidString);
598 ReplaceSameFv = TRUE;
599 LibBfmFreeFd(FdData);
600 return EFI_ABORTED;
601 }
602 //
603 // Interate to insert or replace default setting to Fv
604 //
605 FvInFd = FdData->Fv;
606 do {
607 FvToBeUpdate = FALSE;
608 if (mFvGuidIsSet && FvInFd->IsInputFvFlag) {
609 FvToBeUpdate = TRUE;
610 }
611
612 Status = LibLocateBfv (FdData, &FvId, &FvInFd);
613
614 if (EFI_ERROR (Status)) {
615 printf("Error while locate BFV from FD.\n");
616 LibBfmFreeFd(FdData);
617 return Status;
618 }
619
620 Index = 0;
621 while (Index <= FvInFd->FfsNumbers) {
622 //
623 // Locate the multi-platform ffs in Fv and then replace or delete it.
624 //
625 if (!CompareGuid(&FvInFd->FfsHeader[Index].Name, &EfiNewAddToBfvGuid)) {
626 if (ReplaceSameFv) {
627 FvToBeUpdate = TRUE;
628 }
629 break;
630 }
631 Index ++;
632 }
633
634 if (FvToBeUpdate || (Index <= FvInFd->FfsNumbers)) {
635 if (FvToBeUpdate) {
636 FdIsUpdate = TRUE;
637 if (Index <= FvInFd->FfsNumbers) {
638 //
639 // Override original default data by New File
640 //
641 if (strlen (NewFile) > _MAX_PATH - 1) {
642 printf ("The NewFile name is too long \n");
643 LibBfmFreeFd(FdData);
644 return EFI_ABORTED;
645 }
646 strncpy (FvInFd->FfsAttuibutes[Index].FfsName, NewFile, _MAX_PATH - 1);
647 FvInFd->FfsAttuibutes[Index].FfsName[_MAX_PATH - 1] = 0;
648 } else {
649 FfsLevelFoundFlag = FALSE;
650 FvEncapLevel = 0;
651 NewAddedFfsLevel = 0;
652 //
653 // Determine the new added ffs file level in the FV.
654 //
655 LocalEncapData = FvInFd->EncapData;
656
657 while (LocalEncapData != NULL && !FfsLevelFoundFlag ) {
658 if (LocalEncapData->Type == BFM_ENCAP_TREE_FV) {
659 if (FvEncapLevel == ((UINT8) atoi (FvId + 2) - (UINT8) atoi (FvInFd->FvName + 2))) {
660 //
661 // Found the FFS level in this FV.
662 //
663 LocalEncapDataTemp = LocalEncapData;
664 while (LocalEncapDataTemp != NULL) {
665 if (LocalEncapDataTemp->Type == BFM_ENCAP_TREE_FFS) {
666 NewAddedFfsLevel = LocalEncapDataTemp->Level;
667 FfsLevelFoundFlag = TRUE;
668 break;
669 }
670 if (LocalEncapDataTemp->NextNode != NULL) {
671 LocalEncapDataTemp = LocalEncapDataTemp->NextNode;
672 } else {
673 break;
674 }
675 }
676 }
677 FvEncapLevel ++;
678 }
679
680 if (LocalEncapData->NextNode == NULL) {
681 break;
682 } else {
683 LocalEncapData = LocalEncapData->NextNode;
684 }
685 }
686
687 //
688 // Add the new file into FV.
689 //
690 FvInFd->FfsNumbers += 1;
691 memcpy (FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].FfsName, NewFile, _MAX_PATH);
692 FvInFd->FfsAttuibutes[FvInFd->FfsNumbers].Level = NewAddedFfsLevel;
693 }
694 } else {
695 //
696 // Remove original default data from FV.
697 //
698 FvInFd->FfsAttuibutes[Index].FfsName[0] = '\0';
699 }
700
701 if (TemDir == NULL) {
702 TemDir = getcwd (NULL, _MAX_PATH);
703 if (strlen (TemDir) + strlen (OS_SEP_STR)+ strlen (TEMP_DIR_NAME) > _MAX_PATH - 1) {
704 printf ("The directory is too long \n");
705 LibBfmFreeFd(FdData);
706 return EFI_ABORTED;
707 }
708 strncat (TemDir, OS_SEP_STR, _MAX_PATH - strlen (TemDir) - 1);
709 strncat (TemDir, TEMP_DIR_NAME, _MAX_PATH - strlen (TemDir) - 1);
710 mkdir(TemDir, S_IRWXU | S_IRWXG | S_IRWXO);
711 }
712
713 Status = LibEncapNewFvFile (FvInFd, TemDir, &OutputFileName);
714
715 if (EFI_ERROR (Status)) {
716 printf("Error. The boot firmware volume (BFV) has only the spare space 0x%lx bytes. But the default setting data takes 0x%llx bytes, which can't be inserted into BFV. \n", (unsigned long) GetBfvPadSize (), (unsigned long long) NewFfsLength);
717 LibBfmFreeFd(FdData);
718 return Status;
719 }
720
721 if (FirstInFlag) {
722 //
723 // Write New Fv file into the NewFd file.
724 //
725 Status = LibCreateNewFdCopy (FdInName, FdOutName);
726 if (EFI_ERROR (Status)) {
727 printf("Error while copy from %s to %s file. \n", FdInName, FdOutName);
728 LibBfmFreeFd(FdData);
729 return Status;
730 }
731 FirstInFlag = FALSE;
732 }
733
734 NewFdFile = fopen (FdOutName, "rb+");
735 if (NewFdFile == NULL) {
736 printf("Error while create FD file %s. \n", FdOutName);
737 LibBfmFreeFd(FdData);
738 return EFI_ABORTED;
739 }
740
741 NewFvFile = fopen (OutputFileName, "rb+");
742
743 if (NewFvFile == NULL) {
744 printf("Error while create Fv file %s. \n", OutputFileName);
745 LibBfmFreeFd(FdData);
746 fclose (NewFdFile);
747 return EFI_ABORTED;
748 }
749
750 fseek(NewFvFile,0,SEEK_SET);
751 fseek(NewFvFile,0,SEEK_END);
752
753 NewFvLength = ftell(NewFvFile);
754
755 fseek(NewFvFile,0,SEEK_SET);
756
757 Buffer = malloc ((size_t)NewFvLength);
758
759 if (Buffer == NULL) {
760 LibBfmFreeFd(FdData);
761 fclose (NewFdFile);
762 fclose (NewFvFile);
763 return EFI_ABORTED;
764 }
765
766 if (fread (Buffer, 1, (size_t) NewFvLength, NewFvFile) != (size_t) NewFvLength) {
767 printf("Error while read Fv file %s. \n", OutputFileName);
768 LibBfmFreeFd(FdData);
769 free (Buffer);
770 fclose (NewFdFile);
771 fclose (NewFvFile);
772 return EFI_ABORTED;
773 }
774
775 fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
776 fseek(NewFdFile, FvInFd->ImageAddress, SEEK_SET);
777
778 if (NewFvLength <= FvInFd->FvHeader->FvLength) {
779 if (fwrite (Buffer, 1, (size_t) NewFvLength, NewFdFile) != (size_t) NewFvLength) {
780 printf("Error while write FD file %s. \n", FdOutName);
781 fclose(NewFdFile);
782 fclose (NewFvFile);
783 LibBfmFreeFd(FdData);
784 free (Buffer);
785 return EFI_ABORTED;
786 }
787 } else {
788 printf("Error. The new size of BFV is 0x%llx bytes, which is larger than the previous size of BFV 0x%llx bytes. \n", (unsigned long long) NewFvLength, (unsigned long long) FvInFd->FvHeader->FvLength);
789 free (Buffer);
790 LibBfmFreeFd(FdData);
791 fclose (NewFdFile);
792 fclose (NewFvFile);
793 return EFI_ABORTED;
794 }
795
796 fclose(NewFdFile);
797 fclose(NewFvFile);
798 free (Buffer);
799 Buffer = NULL;
800
801 }
802 FvInFd = FvInFd->FvNext;
803 } while (FvInFd != NULL);
804
805 LibBfmFreeFd(FdData);
806
807 if (TemDir == NULL || !FdIsUpdate) {
808 if (mFvGuidIsSet) {
809 printf ("Fv image with the specified FV Name Guid %s can't be found.\n", mFvNameGuidString);
810 } else {
811 printf ("BFV image can't be found.\n");
812 }
813 return EFI_NOT_FOUND;
814 }
815
816 Status = LibRmDir (TemDir);
817
818 if (EFI_ERROR (Status)) {
819 printf("Error while remove temporary directory. \n");
820 return Status;
821 }
822
823 return EFI_SUCCESS;
824 }
825
826 /**
827
828 The main entry of BFM tool.
829
830 **/
831 int main(
832 int Argc,
833 char *Argv[]
834 )
835 {
836 EFI_STATUS Status;
837 FIRMWARE_DEVICE *FdData;
838 CHAR8 *InFilePath;
839 CHAR8 FullGuidToolDefinition[_MAX_PATH];
840 CHAR8 *FileName;
841 UINTN FileNameIndex;
842 CHAR8 *PathList;
843 UINTN EnvLen;
844 CHAR8 *NewPathList;
845
846 FdData = NULL;
847 PathList = NULL;
848 NewPathList = NULL;
849 EnvLen = 0;
850
851 if (Argc <= 1) {
852 return -1;
853 }
854 FileName = Argv[0];
855 //
856 // Save, skip filename arg
857 //
858 Argc--;
859 Argv++;
860
861 if ((stricmp(Argv[0], "-v") == 0)) {
862 //
863 // Check the revison of BfmLib
864 // BfmLib -v
865 //
866 printf("%s\n", __BUILD_VERSION);
867 return 1;
868
869 }
870 //
871 // Workaroud: the first call to this function
872 // returns a file name ends with dot
873 //
874 #ifndef __GNUC__
875 tmpnam (NULL);
876 #else
877 CHAR8 tmp[] = "/tmp/fileXXXXXX";
878 UINTN Fdtmp;
879 Fdtmp = mkstemp(tmp);
880 close(Fdtmp);
881 #endif
882 //
883 // Get the same path with the application itself
884 //
885 if (strlen (FileName) > _MAX_PATH - 1) {
886 Error (NULL, 0, 2000, "Parameter: Input file name is too long", NULL);
887 return -1;
888 }
889 strncpy (FullGuidToolDefinition, FileName, _MAX_PATH - 1);
890 FullGuidToolDefinition[_MAX_PATH - 1] = 0;
891 FileNameIndex = strlen (FullGuidToolDefinition);
892 while (FileNameIndex != 0) {
893 FileNameIndex --;
894 if (FullGuidToolDefinition[FileNameIndex] == OS_SEP) {
895 FullGuidToolDefinition[FileNameIndex] = 0;
896 break;
897 }
898 }
899 //
900 // Build the path list for Config file scan. The priority is below.
901 // 1. Scan the current path
902 // 2. Scan the same path with the application itself
903 // 3. Scan the current %PATH% of OS environment
904 // 4. Use the build-in default configuration
905 //
906 PathList = getenv("PATH");
907 if (PathList == NULL) {
908 Error (NULL, 0, 1001, "Option: Environment variable 'PATH' does not exist", NULL);
909 return -1;
910 }
911 EnvLen = strlen(PathList);
912 NewPathList = (char *)calloc(
913 strlen (".")
914 + strlen (";")
915 + strlen (FullGuidToolDefinition)
916 + strlen (";")
917 + EnvLen
918 + 1,
919 sizeof(char)
920 );
921 if (NewPathList == NULL) {
922 Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL);
923 PathList = NULL;
924 free (PathList);
925 return -1;
926 }
927 #ifndef __GNUC__
928 sprintf (NewPathList, "%s;%s;%s", ".", FullGuidToolDefinition, PathList);
929 #else
930 sprintf (NewPathList, "%s:%s:%s", ".", FullGuidToolDefinition, PathList);
931 #endif
932
933 PathList = NULL;
934 free (PathList);
935 //
936 // Load Guid Tools definition
937 //
938 InFilePath = SearchConfigFromPathList(NewPathList, mGuidToolDefinition);
939 free (NewPathList);
940 if (InFilePath != NULL) {
941 printf ("\nThe Guid Tool Definition of BfmLib comes from the '%s'. \n", InFilePath);
942 mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (InFilePath);
943 free (InFilePath);
944 } else {
945 //
946 // Use the pre-defined standard guided tools.
947 //
948 printf ("\nThe Guid Tool Definition of BfmLib comes from the build-in default configuration. \n");
949 mParsedGuidedSectionTools = LibPreDefinedGuidedTools ();
950 }
951
952 //
953 // BfmLib -e FdName.Fd
954 //
955 if ((stricmp(Argv[0], "-e") == 0)) {
956
957 if (Argc != 2) {
958 return -1;
959 }
960 //
961 // Extract FFS files.
962 //
963 Status = BfmImageView (Argv[1], NULL, FALSE, &FdData);
964
965 if (EFI_ERROR (Status)) {
966 return -1;
967 }
968
969 if (FdData == NULL) {
970 return -1;
971 }
972
973 LibBfmFreeFd(FdData);
974
975 } else if ((stricmp(Argv[0], "-i") == 0)) {
976 //
977 // Insert FFS files to BFV
978 // BfmLib -i InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
979 //
980 if (Argc == 6) {
981 mFvGuidIsSet = TRUE;
982 mFvNameGuidString = Argv[5];
983 StringToGuid (Argv[5], &mFvNameGuid);
984 Argc -= 2;
985 }
986 if (Argc != 4) {
987 return -1;
988 }
989 Status = BfmImageAdd(Argv[1], Argv[2], Argv[3]);
990
991 if (EFI_ERROR (Status)) {
992 return -1;
993 }
994
995 } else if ((stricmp(Argv[0], "-r") == 0)) {
996 //
997 // Replace FFS files in BFV
998 // BfmLib -r InFdName.Fd FfsName.ffs OutFdName.Fd -g FvNameGuid
999 //
1000 if (Argc == 6) {
1001 mFvGuidIsSet = TRUE;
1002 mFvNameGuidString = Argv[5];
1003 StringToGuid (Argv[5], &mFvNameGuid);
1004 Argc -= 2;
1005 }
1006 if (Argc != 4) {
1007 return -1;
1008 }
1009 Status = BfmImageReplace (Argv[1], Argv[2], Argv[3]);
1010
1011 if (EFI_ERROR (Status)) {
1012 return -1;
1013 }
1014
1015 } else {
1016 //
1017 // Invalid parameter.
1018 //
1019 return -1;
1020 }
1021
1022 return 1;
1023 }
1024