a4740109954f8f0fd00379781459b32cce6d97e7
[people/mcb30/basetools.git] / Source / C / GenFw / GenFw.c
1 /*++\r
2 \r
3 Copyright (c) 2004 - 2007, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14     GenFw.c\r
15 \r
16 Abstract:\r
17 \r
18     Converts a pe32+ image to an FW image type\r
19 \r
20 --*/\r
21 \r
22 #include "WinNtInclude.h"\r
23 \r
24 //\r
25 // List of OS and CPU which support ELF to PE conversion\r
26 //\r
27 #if defined(linux)
28 #if defined (__i386__) || defined(__x86_64__)
29 #define HAVE_ELF
30 #endif
31 #endif
32
33 #ifndef __GNUC__\r
34 #include <windows.h>\r
35 #endif\r
36 #include <stdio.h>\r
37 #include <stdlib.h>\r
38 #include <string.h>\r
39 #include <time.h>\r
40
41 #ifdef HAVE_ELF
42 #include <elf.h>
43 #endif
44 \r
45 #include <Common/UefiBaseTypes.h>\r
46 #include <Common/EfiImage.h>\r
47 \r
48 #include "CommonLib.h"\r
49 #include "EfiUtilityMsgs.c"\r
50 \r
51 //\r
52 // Acpi Table definition\r
53 //\r
54 #include "Acpi.h"\r
55 #include "Acpi1_0.h"\r
56 #include "Acpi2_0.h"\r
57 #include "Acpi3_0.h"\r
58 #include "MemoryMappedConfigurationSpaceAccessTable.h"\r
59 \r
60 //\r
61 // Version of this utility\r
62 //\r
63 #define UTILITY_NAME "GenFw"\r
64 #define UTILITY_MAJOR_VERSION 1\r
65 #define UTILITY_MINOR_VERSION 0\r
66 \r
67 UINT8 *InImageName;\r
68 \r
69 #define FW_DUMMY_IMAGE   0\r
70 #define FW_EFI_IMAGE     1\r
71 #define FW_TE_IMAGE      2\r
72 #define FW_ACPI_IMAGE    3\r
73 \r
74 #define MAX_STRING_LENGTH 100\r
75 \r
76 STATIC\r
77 VOID\r
78 Version (\r
79   VOID\r
80   )\r
81 {\r
82   printf ("%s v%d.%d -EDK Utility mainly for Converting a pe32+ image to an FW image type.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
83   printf ("Copyright (c) 2007 Intel Corporation. All rights reserved.\n");\r
84 }\r
85 \r
86 STATIC\r
87 VOID\r
88 Usage (\r
89   VOID\r
90   )\r
91 {\r
92   Version();\r
93   printf ("\nUsage: " UTILITY_NAME " [inputfilename]\n\\r
94         -o, --outputfile [FileName]\n\\r
95         -e, --efiImage <BASE|SEC|PEI_CORE|PEIM|DXE_CORE|DXE_DRIVER|\n\\r
96                         DXE_RUNTIME_DRIVER|DXE_SAL_DRIVER|DXE_SMM_DRIVER|\n\\r
97                         UEFI_DRIVER|UEFI_APPLICATION|SECURITY_CORE|\n\\r
98                         COMBINED_PEIM_DRIVER|PIC_PEIM|RELOCATABLE_PEIM|\n\\r
99                         BS_DRIVER|RT_DRIVER|SAL_RT_DRIVER|APPLICATION>\n\\r
100         -c, --acpi\n\\r
101         -t, --terse\n\\r
102         -h, --help\n\\r
103         -V, --version\n");\r
104 }\r
105 \r
106 static\r
107 STATUS\r
108 CheckAcpiTable (\r
109   VOID      *AcpiTable,\r
110   UINT32    Length\r
111   )\r
112 /*++\r
113 \r
114 Routine Description:\r
115   \r
116   Check Acpi Table \r
117 \r
118 Arguments:\r
119 \r
120   AcpiTable     Buffer for AcpiSection\r
121   Length        AcpiSection Length\r
122 \r
123 Returns:\r
124 \r
125   0             success\r
126   non-zero      otherwise\r
127 \r
128 --*/\r
129 {\r
130   EFI_ACPI_DESCRIPTION_HEADER                   *AcpiHeader;\r
131   EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE  *Facs;\r
132   UINT32                                        ExpectedLength;\r
133 \r
134   AcpiHeader = (EFI_ACPI_DESCRIPTION_HEADER *)AcpiTable;\r
135 \r
136   //\r
137   // Generic check for AcpiTable length.\r
138   //\r
139   if (AcpiHeader->Length > Length) {\r
140     Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass AcpiTable Length check");\r
141     return STATUS_ERROR;\r
142   }\r
143 \r
144   //\r
145   // Currently, we only check must-have tables: FADT, FACS, DSDT,\r
146   // and some important tables: MADT, MCFG.\r
147   //\r
148   switch (AcpiHeader->Signature) {\r
149 \r
150   //\r
151   // "FACP" Fixed ACPI Description Table\r
152   //\r
153   case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:\r
154     switch (AcpiHeader->Revision) {\r
155     case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
156       ExpectedLength = sizeof(EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
157       break;\r
158     case EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
159       ExpectedLength = sizeof(EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
160       break;\r
161     case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION:\r
162       ExpectedLength = sizeof(EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE);\r
163       break;\r
164     default:\r
165       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP revision check");\r
166       return STATUS_ERROR;\r
167     }\r
168     if (ExpectedLength != AcpiHeader->Length) {\r
169       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACP Length check");\r
170       return STATUS_ERROR;\r
171     }\r
172     break;\r
173 \r
174   //\r
175   // "FACS" Firmware ACPI Control Structure\r
176   //\r
177   case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:\r
178     Facs = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)AcpiTable;\r
179     if ((Facs->Version != 0) &&\r
180         (Facs->Version != EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&\r
181         (Facs->Version != EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION)){\r
182       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS version check");\r
183       return STATUS_ERROR;\r
184     }\r
185     if ((Facs->Length != sizeof(EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&\r
186         (Facs->Length != sizeof(EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE)) &&\r
187         (Facs->Length != sizeof(EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE))) {\r
188       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass FACS Length check");\r
189       return STATUS_ERROR;\r
190     }\r
191     break;\r
192 \r
193   //\r
194   // "DSDT" Differentiated System Description Table\r
195   //\r
196   case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:\r
197     if (AcpiHeader->Revision > EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_REVISION) {\r
198       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT revision check");\r
199       return STATUS_ERROR;\r
200     }\r
201     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER)) {\r
202       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass DSDT Length check");\r
203       return STATUS_ERROR;\r
204     }\r
205     break;\r
206 \r
207   //\r
208   // "APIC" Multiple APIC Description Table\r
209   //\r
210   case EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:\r
211     if ((AcpiHeader->Revision != EFI_ACPI_1_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&\r
212         (AcpiHeader->Revision != EFI_ACPI_2_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION) &&\r
213         (AcpiHeader->Revision != EFI_ACPI_3_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION)) {\r
214       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC revision check");\r
215       return STATUS_ERROR;\r
216     }\r
217     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT32) + sizeof(UINT32)) {\r
218       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass APIC Length check");\r
219       return STATUS_ERROR;\r
220     }\r
221     break;\r
222 \r
223   //\r
224   // "MCFG" PCI Express Memory Mapped Configuration Space Base Address Description Table\r
225   //\r
226   case EFI_ACPI_3_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE:\r
227     if (AcpiHeader->Revision != EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_SPACE_ACCESS_TABLE_REVISION) {\r
228       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG revision check");\r
229       return STATUS_ERROR;\r
230     }\r
231     if (AcpiHeader->Length <= sizeof(EFI_ACPI_DESCRIPTION_HEADER) + sizeof(UINT64)) {\r
232       Error (NULL, 0, 0, "CheckAcpiTable", "failed to pass MCFG Length check");\r
233       return STATUS_ERROR;\r
234     }\r
235     break;\r
236 \r
237   //\r
238   // Other table pass check\r
239   //\r
240   default:\r
241     break;\r
242   }\r
243 \r
244   return STATUS_SUCCESS;\r
245 }\r
246 \r
247 static\r
248 STATUS\r
249 FCopyFile (\r
250   FILE    *in,\r
251   FILE    *out\r
252   )\r
253 {\r
254   UINT32  filesize;\r
255   UINT32  offset;\r
256   UINT32  length;\r
257   UINT8 Buffer[8 * 1024];\r
258 \r
259   fseek (in, 0, SEEK_END);\r
260   filesize = ftell (in);\r
261 \r
262   fseek (in, 0, SEEK_SET);\r
263   fseek (out, 0, SEEK_SET);\r
264 \r
265   offset = 0;\r
266   while (offset < filesize) {\r
267     length = sizeof (Buffer);\r
268     if (filesize - offset < length) {\r
269       length = filesize - offset;\r
270     }\r
271 \r
272     fread (Buffer, length, 1, in);\r
273     fwrite (Buffer, length, 1, out);\r
274     offset += length;\r
275   }\r
276 \r
277   if ((UINT32 ) ftell (out) != filesize) {\r
278     Error (NULL, 0, 0, "write error", NULL);\r
279     return STATUS_ERROR;\r
280   }\r
281 \r
282   return STATUS_SUCCESS;\r
283 }\r
284 \r
285 static\r
286 STATUS\r
287 FReadFile (\r
288   FILE    *in,\r
289   VOID    **Buffer,\r
290   UINTN   *Length\r
291   )\r
292 {\r
293   fseek (in, 0, SEEK_END);\r
294   *Length = ftell (in);\r
295   *Buffer = malloc (*Length);\r
296   fseek (in, 0, SEEK_SET);\r
297   fread (*Buffer, *Length, 1, in);\r
298   return STATUS_SUCCESS;\r
299 }\r
300 \r
301 static\r
302 STATUS\r
303 FWriteFile (\r
304   FILE    *out,\r
305   VOID    *Buffer,\r
306   UINTN   Length\r
307   )\r
308 {\r
309   fseek (out, 0, SEEK_SET);\r
310   fwrite (Buffer, Length, 1, out);\r
311   if ((UINT32 ) ftell (out) != Length) {\r
312     Error (NULL, 0, 0, "write error", NULL);\r
313     return STATUS_ERROR;\r
314   }\r
315   free (Buffer);\r
316   return STATUS_SUCCESS;\r
317 }\r
318 \r
319 #ifdef HAVE_ELF
320 INTN
321 IsElfHeader(
322   UINT8  *FileBuffer
323 )
324 {
325   return (FileBuffer[EI_MAG0] == ELFMAG0
326     && FileBuffer[EI_MAG1] == ELFMAG1
327     && FileBuffer[EI_MAG2] == ELFMAG2
328     && FileBuffer[EI_MAG3] == ELFMAG3);
329 }
330
331 typedef Elf32_Shdr Elf_Shdr;
332 typedef Elf32_Ehdr Elf_Ehdr;
333 typedef Elf32_Rel Elf_Rel;
334 typedef Elf32_Sym Elf_Sym;
335 #define ELFCLASS ELFCLASS32
336 #define ELF_R_TYPE(r) ELF32_R_TYPE(r)
337 #define ELF_R_SYM(r) ELF32_R_SYM(r)
338
339 //
340 // Well known ELF structures.
341 //
342 Elf_Ehdr *Ehdr;
343 Elf_Shdr *ShdrBase;
344
345 //
346 // PE section alignment.
347 //
348 const UINT32 CoffAlignment = 0x20;
349 const UINT32 CoffNbrSections = 4;
350
351 //
352 // Current offset in coff file.
353 //
354 UINT32 CoffOffset;
355
356 //
357 // Result Coff file in memory.
358 //
359 UINT8 *CoffFile;
360
361 //
362 // Offset in Coff file of headers and sections.
363 //
364 UINT32 NtHdrOffset;
365 UINT32 TableOffset;
366 UINT32 TextOffset;
367 UINT32 DataOffset;
368 UINT32 RelocOffset;
369
370 //
371 // ELF sections to offset in Coff file.
372 //
373 UINT32 *CoffSectionsOffset;
374
375 EFI_IMAGE_BASE_RELOCATION *CoffBaseRel;
376 UINT16 *CoffEntryRel;
377
378 UINT32
379 CoffAlign(
380   UINT32 Offset
381   )
382 {
383   return (Offset + CoffAlignment - 1) & ~(CoffAlignment - 1);
384 }
385
386 Elf_Shdr *
387 GetShdrByIndex(
388   UINT32 Num
389   )
390 {
391   if (Num >= Ehdr->e_shnum)
392     return NULL;
393   return (Elf_Shdr*)((UINT8*)ShdrBase + Num * Ehdr->e_shentsize);
394 }
395
396 INTN
397 CheckElfHeader(
398   VOID
399   )
400 {\r
401   //
402   // Note: Magic has already been tested.
403   //
404   if (Ehdr->e_ident[EI_CLASS] != ELFCLASS)
405     return 0;
406   if (Ehdr->e_ident[EI_DATA] != ELFDATA2LSB)
407     return 0;
408   if (Ehdr->e_type != ET_EXEC)
409     return 0;
410   if (Ehdr->e_machine != EM_386)
411     return 0;
412   if (Ehdr->e_version != EV_CURRENT)
413     return 0;
414 \r
415   //\r
416   // Find the section header table\r
417   // 
418   ShdrBase = (Elf_Shdr *)((UINT8 *)Ehdr + Ehdr->e_shoff);
419
420   CoffSectionsOffset = (UINT32 *)malloc(Ehdr->e_shnum * sizeof (UINT32));\r
421
422   memset(CoffSectionsOffset, 0, Ehdr->e_shnum * sizeof(UINT32));\r
423   return 1;
424 }
425
426 int
427 IsTextShdr(
428   Elf_Shdr *Shdr
429   )
430 {
431   return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == SHF_ALLOC;
432 }
433 \r
434 int
435 IsDataShdr(
436   Elf_Shdr *Shdr
437   )
438 {
439   return (Shdr->sh_flags & (SHF_WRITE | SHF_ALLOC)) == (SHF_ALLOC | SHF_WRITE);
440 }
441
442 void
443 CreateSectionHeader(
444   const char *Name,
445   UINT32     Offset,
446   UINT32     Size,
447   UINT32     Flags
448   )
449 {
450   EFI_IMAGE_SECTION_HEADER *Hdr;
451   Hdr = (EFI_IMAGE_SECTION_HEADER*)(CoffFile + TableOffset);
452
453   strcpy(Hdr->Name, Name);
454   Hdr->Misc.VirtualSize = Size;
455   Hdr->VirtualAddress = Offset;
456   Hdr->SizeOfRawData = Size;
457   Hdr->PointerToRawData = Offset;
458   Hdr->PointerToRelocations = 0;
459   Hdr->PointerToLinenumbers = 0;
460   Hdr->NumberOfRelocations = 0;
461   Hdr->NumberOfLinenumbers = 0;
462   Hdr->Characteristics = Flags;
463
464   TableOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
465 }
466
467 void
468 ScanSections(
469   VOID
470   )
471 {
472   UINT32 i;
473   EFI_IMAGE_DOS_HEADER *DosHdr;
474   EFI_IMAGE_NT_HEADERS *NtHdr;
475   UINT32 CoffEntry = 0;
476
477   CoffOffset = 0;
478
479   //
480   // Coff file start with a DOS header.
481   //
482   CoffOffset = sizeof(EFI_IMAGE_DOS_HEADER) + 0x40;
483   NtHdrOffset = CoffOffset;
484   CoffOffset += sizeof(EFI_IMAGE_NT_HEADERS);
485   TableOffset = CoffOffset;
486   CoffOffset += CoffNbrSections * sizeof(EFI_IMAGE_SECTION_HEADER);
487
488   //
489   // First text sections.
490   //
491   CoffOffset = CoffAlign(CoffOffset);
492   TextOffset = CoffOffset;
493   for (i = 0; i < Ehdr->e_shnum; i++) {
494     Elf_Shdr *shdr = GetShdrByIndex(i);
495     if (IsTextShdr(shdr)) {\r
496       //\r
497       // Align the coff offset to meet with the alignment requirement of section\r
498       // itself.\r
499       // \r
500       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
501         CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
502       }\r
503 \r
504       /* Relocate entry.  */
505       if ((Ehdr->e_entry >= shdr->sh_addr) && \r
506           (Ehdr->e_entry < shdr->sh_addr + shdr->sh_size)) {
507         CoffEntry = CoffOffset + Ehdr->e_entry - shdr->sh_addr;
508       }
509       CoffSectionsOffset[i] = CoffOffset;\r
510       CoffOffset += shdr->sh_size;
511     }\r
512   }\r
513   CoffOffset = CoffAlign(CoffOffset);
514 \r
515   //
516   //  Then data sections.
517   //
518   DataOffset = CoffOffset;
519   for (i = 0; i < Ehdr->e_shnum; i++) {
520     Elf_Shdr *shdr = GetShdrByIndex(i);
521     if (IsDataShdr(shdr)) {\r
522       //\r
523       // Align the coff offset to meet with the alignment requirement of section\r
524       // itself.\r
525       // \r
526       if ((shdr->sh_addralign != 0) && (shdr->sh_addralign != 1)) {\r
527         CoffOffset = (CoffOffset + shdr->sh_addralign - 1) & ~(shdr->sh_addralign - 1);\r
528       }
529      \r
530       CoffSectionsOffset[i] = CoffOffset;
531       CoffOffset += shdr->sh_size;
532     }
533   }
534   CoffOffset = CoffAlign(CoffOffset);
535
536   RelocOffset = CoffOffset;  
537
538   //
539   // Allocate base Coff file.  Will be expanded later for relocations. 
540   //
541   CoffFile = (UINT8 *)malloc(CoffOffset);
542   memset(CoffFile, 0, CoffOffset);
543
544   //
545   // Fill headers.
546   //
547   DosHdr = (EFI_IMAGE_DOS_HEADER *)CoffFile;
548   DosHdr->e_magic = EFI_IMAGE_DOS_SIGNATURE;
549   DosHdr->e_lfanew = NtHdrOffset;
550
551   NtHdr = (EFI_IMAGE_NT_HEADERS*)(CoffFile + NtHdrOffset);
552
553   NtHdr->Signature = EFI_IMAGE_NT_SIGNATURE;
554
555   NtHdr->FileHeader.Machine = EFI_IMAGE_MACHINE_IA32;
556   NtHdr->FileHeader.NumberOfSections = CoffNbrSections;
557   NtHdr->FileHeader.TimeDateStamp = time(NULL);
558   NtHdr->FileHeader.PointerToSymbolTable = 0;
559   NtHdr->FileHeader.NumberOfSymbols = 0;
560   NtHdr->FileHeader.SizeOfOptionalHeader = sizeof(NtHdr->OptionalHeader);
561   NtHdr->FileHeader.Characteristics = EFI_IMAGE_FILE_EXECUTABLE_IMAGE
562     | EFI_IMAGE_FILE_LINE_NUMS_STRIPPED
563     | EFI_IMAGE_FILE_LOCAL_SYMS_STRIPPED
564     | EFI_IMAGE_FILE_32BIT_MACHINE;
565   
566   NtHdr->OptionalHeader.Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
567   NtHdr->OptionalHeader.SizeOfCode = DataOffset - TextOffset;
568   NtHdr->OptionalHeader.SizeOfInitializedData = RelocOffset - DataOffset;
569   NtHdr->OptionalHeader.SizeOfUninitializedData = 0;
570   NtHdr->OptionalHeader.AddressOfEntryPoint = CoffEntry;
571   NtHdr->OptionalHeader.BaseOfCode = TextOffset;
572
573   NtHdr->OptionalHeader.BaseOfData = DataOffset;
574   NtHdr->OptionalHeader.ImageBase = 0;
575   NtHdr->OptionalHeader.SectionAlignment = CoffAlignment;
576   NtHdr->OptionalHeader.FileAlignment = CoffAlignment;
577   NtHdr->OptionalHeader.SizeOfImage = 0;
578
579   NtHdr->OptionalHeader.SizeOfHeaders = TextOffset;
580   NtHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_NUMBER_OF_DIRECTORY_ENTRIES;
581
582   //
583   // Section headers.
584   //
585   CreateSectionHeader (".text", TextOffset, DataOffset - TextOffset,
586            EFI_IMAGE_SCN_CNT_CODE
587            | EFI_IMAGE_SCN_MEM_EXECUTE
588            | EFI_IMAGE_SCN_MEM_READ);
589   CreateSectionHeader (".data", DataOffset, RelocOffset - DataOffset,
590            EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
591            | EFI_IMAGE_SCN_MEM_WRITE
592            | EFI_IMAGE_SCN_MEM_READ);
593 }
594
595 void
596 WriteSections(
597   int   (*Filter)(Elf_Shdr *)
598   )
599 {
600   UINT32 Idx;
601
602   //
603   // First: copy sections.
604   //
605   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
606     Elf_Shdr *Shdr = GetShdrByIndex(Idx);
607     if ((*Filter)(Shdr)) {
608       switch (Shdr->sh_type) {
609       case SHT_PROGBITS:
610   /* Copy.  */
611   memcpy(CoffFile + CoffSectionsOffset[Idx],
612          (UINT8*)Ehdr + Shdr->sh_offset,
613          Shdr->sh_size);
614   break;
615       case SHT_NOBITS:
616   memset(CoffFile + CoffSectionsOffset[Idx], 0, Shdr->sh_size);
617   break;
618       default:
619   Error (NULL, 0, 0, InImageName, "unhandle section type %x",
620          (UINTN)Shdr->sh_type);
621       }
622     }
623   }
624
625   //
626   // Second: apply relocations.
627   //
628   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
629     Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
630     if (RelShdr->sh_type != SHT_REL)
631       continue;
632     Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
633     UINT32 SecOffset = CoffSectionsOffset[RelShdr->sh_info];
634     if (RelShdr->sh_type == SHT_REL && (*Filter)(SecShdr)) {
635       UINT32 RelIdx;
636       Elf_Shdr *SymtabShdr = GetShdrByIndex(RelShdr->sh_link);
637       UINT8 *Symtab = (UINT8*)Ehdr + SymtabShdr->sh_offset;
638
639       for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
640   Elf_Rel *Rel = (Elf_Rel *)((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
641   Elf_Sym *Sym = (Elf_Sym *)
642     (Symtab + ELF_R_SYM(Rel->r_info) * SymtabShdr->sh_entsize);
643   Elf_Shdr *SymShdr;
644   UINT8 *Targ;
645
646   if (Sym->st_shndx == SHN_UNDEF
647       || Sym->st_shndx == SHN_ABS
648       || Sym->st_shndx > Ehdr->e_shnum) {
649     Error (NULL, 0, 0, InImageName, "bad symbol definition");
650   }
651   SymShdr = GetShdrByIndex(Sym->st_shndx);
652
653   //
654   // Note: r_offset in a memory address.
655   //  Convert it to a pointer in the coff file.
656   //
657   Targ = CoffFile + SecOffset + (Rel->r_offset - SecShdr->sh_addr);
658
659   switch (ELF_R_TYPE(Rel->r_info)) {
660   case R_386_NONE:
661     break;
662   case R_386_32:
663     //
664     // Absolute relocation.
665     //
666     *(UINT32 *)Targ = *(UINT32 *)Targ - SymShdr->sh_addr
667       + CoffSectionsOffset[Sym->st_shndx];
668     break;
669   case R_386_PC32:
670     //
671     // Relative relocation: Symbol - Ip + Addend
672     //
673     *(UINT32 *)Targ = *(UINT32 *)Targ
674       + (CoffSectionsOffset[Sym->st_shndx] - SymShdr->sh_addr)
675       - (SecOffset - SecShdr->sh_addr);
676     break;
677   default:
678     Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
679      ELF_R_TYPE(Rel->r_info));
680   }
681       }
682     }
683   }
684 }
685
686 void
687 CoffAddFixupEntry(
688   UINT16 Val
689   )
690 {
691   *CoffEntryRel = Val;
692   CoffEntryRel++;
693   CoffBaseRel->SizeOfBlock += 2;
694   CoffOffset += 2;
695 }
696
697 void
698 CoffAddFixup(
699   UINT32 Offset,
700   UINT8  Type
701   )
702 {
703   if (CoffBaseRel == NULL
704       || CoffBaseRel->VirtualAddress != (Offset & ~0xfff)) {
705     if (CoffBaseRel != NULL) {
706       //
707       // Add a null entry (is it required ?)
708       //
709       CoffAddFixupEntry (0);
710       //
711       // Pad for alignment.
712       //
713       if (CoffOffset % 4 != 0)
714   CoffAddFixupEntry (0);
715     }
716       
717     CoffFile = realloc
718       (CoffFile,
719        CoffOffset + sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
720     memset(CoffFile + CoffOffset, 0,
721      sizeof(EFI_IMAGE_BASE_RELOCATION) + 2*0x1000);
722
723     CoffBaseRel = (EFI_IMAGE_BASE_RELOCATION*)(CoffFile + CoffOffset);
724     CoffBaseRel->VirtualAddress = Offset & ~0xfff;
725     CoffBaseRel->SizeOfBlock = sizeof(EFI_IMAGE_BASE_RELOCATION);
726
727     CoffEntryRel = (UINT16 *)(CoffBaseRel + 1);
728     CoffOffset += sizeof(EFI_IMAGE_BASE_RELOCATION);
729   }
730
731   //
732   // Fill the entry.
733   //
734   CoffAddFixupEntry((Type << 12) | (Offset & 0xfff));
735 }
736
737 void
738 WriteRelocations(
739   VOID
740   )
741 {
742   UINT32 Idx;
743   EFI_IMAGE_NT_HEADERS *NtHdr;
744   EFI_IMAGE_DATA_DIRECTORY *Dir;
745
746   for (Idx = 0; Idx < Ehdr->e_shnum; Idx++) {
747     Elf_Shdr *RelShdr = GetShdrByIndex(Idx);
748     if (RelShdr->sh_type == SHT_REL) {
749       Elf_Shdr *SecShdr = GetShdrByIndex(RelShdr->sh_info);
750       if (IsTextShdr(SecShdr) || IsDataShdr(SecShdr)) {
751   UINT32 RelIdx;
752   for (RelIdx = 0; RelIdx < RelShdr->sh_size; RelIdx += RelShdr->sh_entsize) {
753     Elf_Rel *Rel = (Elf_Rel *)
754       ((UINT8*)Ehdr + RelShdr->sh_offset + RelIdx);
755     switch (ELF_R_TYPE(Rel->r_info)) {
756     case R_386_NONE:
757     case R_386_PC32:
758       break;
759     case R_386_32:
760       CoffAddFixup(CoffSectionsOffset[RelShdr->sh_info]
761        + (Rel->r_offset - SecShdr->sh_addr),
762        EFI_IMAGE_REL_BASED_HIGHLOW);
763       break;
764     default:
765       Error (NULL, 0, 0, InImageName, "unhandled relocation type %x",
766        ELF_R_TYPE(Rel->r_info));
767     }
768   }
769       }
770     }
771   }
772
773   //
774   // Pad by adding empty entries. 
775   //
776   while (CoffOffset & (CoffAlignment - 1)) {
777     CoffAddFixupEntry(0);
778   }
779
780   CreateSectionHeader (".reloc", RelocOffset, CoffOffset - RelocOffset,
781            EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
782            | EFI_IMAGE_SCN_MEM_DISCARDABLE
783            | EFI_IMAGE_SCN_MEM_READ);
784
785   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
786   Dir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
787   Dir->VirtualAddress = RelocOffset;
788   Dir->Size = CoffOffset - RelocOffset;
789 }
790
791 void
792 WriteDebug(
793   VOID
794   )
795 {
796   UINT32 Len = strlen(InImageName) + 1;
797   UINT32 DebugOffset = CoffOffset;
798   EFI_IMAGE_NT_HEADERS *NtHdr;
799   EFI_IMAGE_DATA_DIRECTORY *DataDir;
800   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *Dir;
801   EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY *Nb10;
802
803   CoffOffset += sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)
804     + sizeof(EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)
805     + Len;
806   CoffOffset = CoffAlign(CoffOffset);
807
808   CoffFile = realloc
809     (CoffFile, CoffOffset);
810   memset(CoffFile + DebugOffset, 0, CoffOffset - DebugOffset);
811   
812   Dir = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY*)(CoffFile + DebugOffset);
813   Dir->Type = EFI_IMAGE_DEBUG_TYPE_CODEVIEW;
814   Dir->SizeOfData = sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY) + Len;
815   Dir->RVA = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
816   Dir->FileOffset = DebugOffset + sizeof(EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
817   
818   Nb10 = (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY*)(Dir + 1);
819   Nb10->Signature = CODEVIEW_SIGNATURE_NB10;
820   strcpy ((UINT8 *)(Nb10 + 1), InImageName);
821
822   CreateSectionHeader (".debug", DebugOffset, CoffOffset - DebugOffset,
823            EFI_IMAGE_SCN_CNT_INITIALIZED_DATA
824            | EFI_IMAGE_SCN_MEM_DISCARDABLE
825            | EFI_IMAGE_SCN_MEM_READ);
826
827   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
828   DataDir = &NtHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG];
829   DataDir->VirtualAddress = DebugOffset;
830   DataDir->Size = CoffOffset - DebugOffset;
831 }
832
833 void
834 ConvertElf (
835   UINT8  **FileBuffer,
836   UINTN *FileLength
837   )
838 {
839   EFI_IMAGE_NT_HEADERS *NtHdr;
840
841   //
842   // Check header, read section table.
843   //
844   Ehdr = (Elf32_Ehdr*)*FileBuffer;
845   if (!CheckElfHeader())
846     return;
847
848   //
849   // Compute sections new address.
850   //
851   ScanSections();
852
853   //
854   // Write and relocate sections.
855   //
856   WriteSections(IsTextShdr);
857   WriteSections(IsDataShdr);
858
859   //
860   // Translate and write relocations.
861   //
862   WriteRelocations();
863
864   //
865   // Write debug info.
866   //
867   WriteDebug();
868
869   NtHdr = (EFI_IMAGE_NT_HEADERS *)(CoffFile + NtHdrOffset);
870   NtHdr->OptionalHeader.SizeOfImage = CoffOffset;
871
872   //
873   // Replace.
874   //
875   free(*FileBuffer);
876   *FileBuffer = CoffFile;
877   *FileLength = CoffOffset;
878 }
879 #endif // HAVE_ELF
880
881 int\r
882 main (\r
883   int  argc,\r
884   char *argv[]\r
885   )\r
886 /*++\r
887 \r
888 Routine Description:\r
889 \r
890   Main function.\r
891 \r
892 Arguments:\r
893 \r
894   argc - Number of command line parameters.\r
895   argv - Array of pointers to command line parameter strings.\r
896 \r
897 Returns:\r
898   STATUS_SUCCESS - Utility exits successfully.\r
899   STATUS_ERROR   - Some error occurred during execution.\r
900 \r
901 --*/\r
902 {\r
903   UINT32            Type;\r
904   UINT8             *OutImageName;\r
905   UINT8             *ModuleType;\r
906   CHAR8             FileName[MAX_STRING_LENGTH];\r
907   UINT8             OutImageType;\r
908   FILE              *fpIn;\r
909   FILE              *fpOut;\r
910   VOID              *ZeroBuffer;\r
911   UINT32            Index;\r
912   UINT32            Index1;\r
913   UINT32            Index2;\r
914   UINTN             AllignedRelocSize;\r
915   UINT8             *FileBuffer;\r
916   UINTN             FileLength;\r
917   RUNTIME_FUNCTION  *RuntimeFunction;\r
918   UNWIND_INFO       *UnwindInfo;\r
919   STATUS            Status;\r
920 \r
921   EFI_TE_IMAGE_HEADER          TEImageHeader;\r
922   EFI_IMAGE_SECTION_HEADER     *SectionHeader;\r
923   EFI_IMAGE_DOS_HEADER         *DosHdr;\r
924   EFI_IMAGE_NT_HEADERS         *PeHdr;\r
925   EFI_IMAGE_OPTIONAL_HEADER32  *Optional32;\r
926   EFI_IMAGE_OPTIONAL_HEADER64  *Optional64;\r
927   EFI_IMAGE_DOS_HEADER         BackupDosHdr;\r
928 \r
929 \r
930   SetUtilityName (UTILITY_NAME);\r
931 \r
932   //\r
933   // Assign to fix compile warning\r
934   //\r
935   InImageName       = NULL;\r
936   OutImageName      = NULL;\r
937   ModuleType        = NULL;\r
938   OutImageType      = FW_DUMMY_IMAGE;\r
939   Type              = 0;\r
940   Status            = STATUS_SUCCESS;\r
941   FileBuffer        = NULL;\r
942   fpIn              = NULL;\r
943   fpOut             = NULL;\r
944 \r
945   if (argc == 1) {\r
946     Usage();\r
947     return STATUS_ERROR;\r
948   }\r
949   \r
950   argc --;\r
951   argv ++;  \r
952 \r
953   if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
954     Usage();\r
955     return STATUS_ERROR;    \r
956   }\r
957 \r
958   if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--version") == 0)) {\r
959     Version();\r
960     return STATUS_ERROR;    \r
961   }\r
962   \r
963   while (argc > 0) {\r
964     if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
965       OutImageName = argv[1];\r
966       argc -= 2;\r
967       argv += 2;\r
968       continue; \r
969     }\r
970 \r
971     if ((stricmp (argv[0], "-e") == 0) || (stricmp (argv[0], "--efiImage") == 0)) {\r
972       ModuleType   = argv[1];\r
973       if (OutImageType == FW_DUMMY_IMAGE) {\r
974         OutImageType = FW_EFI_IMAGE;\r
975       }\r
976       argc -= 2;\r
977       argv += 2;\r
978       continue;\r
979     }\r
980 \r
981     if ((stricmp (argv[0], "-c") == 0) || (stricmp (argv[0], "--acpi") == 0)) {\r
982       OutImageType = FW_ACPI_IMAGE;\r
983       argc --;\r
984       argv ++;\r
985       continue;\r
986     }\r
987 \r
988     if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--terse") == 0)) {\r
989       OutImageType = FW_TE_IMAGE;\r
990       argc --;\r
991       argv ++;\r
992       continue;\r
993     }\r
994 \r
995     InImageName = argv[0];\r
996     argc --;\r
997     argv ++;\r
998   }\r
999   \r
1000   if (OutImageType == FW_DUMMY_IMAGE) {\r
1001     Error (NULL, 0, 0, NULL, "No action specified, such as -e, -c or -t\n");\r
1002     Usage ();\r
1003     return STATUS_ERROR;    \r
1004   }\r
1005 \r
1006   //\r
1007   // Following code to convert dll to efi image or te image.\r
1008   // Get new image type\r
1009   //\r
1010   if ((OutImageType == FW_EFI_IMAGE) || (OutImageType == FW_TE_IMAGE)) {\r
1011     if (ModuleType == NULL) {\r
1012       Error (NULL, 0, 0, NULL, "No ModuleType specified, such as PEIM, DXE_DRIVER\n");\r
1013       Usage ();\r
1014       goto Finish;\r
1015     }\r
1016     \r
1017     if (stricmp (ModuleType, "BASE") == 0 ||\r
1018         stricmp (ModuleType, "SEC") == 0 ||\r
1019         stricmp (ModuleType, "SECURITY_CORE") == 0 ||\r
1020         stricmp (ModuleType, "PEI_CORE") == 0 ||\r
1021         stricmp (ModuleType, "PEIM") == 0 ||\r
1022         stricmp (ModuleType, "COMBINED_PEIM_DRIVER") == 0 ||\r
1023         stricmp (ModuleType, "PIC_PEIM") == 0 ||\r
1024         stricmp (ModuleType, "RELOCATABLE_PEIM") == 0 ||\r
1025         stricmp (ModuleType, "DXE_CORE") == 0 ||\r
1026         stricmp (ModuleType, "BS_DRIVER") == 0  ||\r
1027         stricmp (ModuleType, "DXE_DRIVER") == 0 ||\r
1028         stricmp (ModuleType, "DXE_SMM_DRIVER") == 0  ||\r
1029         stricmp (ModuleType, "UEFI_DRIVER") == 0) {\r
1030       Type = EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER;\r
1031   \r
1032     } else if (stricmp (ModuleType, "UEFI_APPLICATION") == 0 || \r
1033                stricmp (ModuleType, "APPLICATION") == 0) {\r
1034       Type = EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION;\r
1035   \r
1036     } else if (stricmp (ModuleType, "DXE_RUNTIME_DRIVER") == 0 || \r
1037                stricmp (ModuleType, "RT_DRIVER") == 0) {\r
1038       Type = EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER;\r
1039   \r
1040     } else if (stricmp (ModuleType, "DXE_SAL_DRIVER") == 0 || \r
1041                stricmp (ModuleType, "SAL_RT_DRIVER") == 0) {\r
1042       Type = EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER;\r
1043   \r
1044     } else {\r
1045       Error (NULL, 0, 0, ModuleType, "%s is not one valid Module type.\n");\r
1046       Usage ();\r
1047       goto Finish;\r
1048     }\r
1049   }\r
1050 \r
1051   //\r
1052   // get InImageName from stdin\r
1053   //\r
1054   if (InImageName == NULL) {\r
1055     fscanf (stdin, "%s", FileName);\r
1056     InImageName = (UINT8 *) FileName;\r
1057   }\r
1058 \r
1059   //\r
1060   // Open input file\r
1061   //\r
1062   fpIn = fopen (InImageName, "rb");\r
1063   if (!fpIn) {\r
1064     Error (NULL, 0, 0, InImageName, "failed to open input file for reading");\r
1065     goto Finish;\r
1066   }\r
1067 \r
1068   FReadFile (fpIn, (VOID **)&FileBuffer, &FileLength);\r
1069   fclose (fpIn);\r
1070 \r
1071   //\r
1072   // Open output file and Write image into the output file.\r
1073   // if OutImageName == NULL, output data to stdout.\r
1074   //\r
1075   if (OutImageName == NULL) {\r
1076     fpOut = stdout; // binary stream can't be output to string strem stdout\r
1077                     // because 0x0A can be auto converted to 0x0D 0x0A.\r
1078   } else {\r
1079     fpOut = fopen (OutImageName, "w+b");\r
1080   }\r
1081   if (!fpOut) {\r
1082     Error (NULL, 0, 0, OutImageName, "could not open output file for writing");\r
1083     goto Finish;\r
1084   }
1085 \r
1086   //\r
1087   // Convert EFL image to PeImage\r
1088   //\r
1089 #ifdef HAVE_ELF
1090   if (IsElfHeader(FileBuffer)) {
1091     ConvertElf(&FileBuffer, &FileLength);
1092   }
1093 #endif\r
1094 \r
1095   //\r
1096   // Read the dos & pe hdrs of the image\r
1097   //\r
1098   DosHdr = (EFI_IMAGE_DOS_HEADER *)FileBuffer;\r
1099   if (DosHdr->e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
1100     Error (NULL, 0, 0, InImageName, "DOS header signature not found in source image");\r
1101     goto Finish;\r
1102   }\r
1103 \r
1104   PeHdr = (EFI_IMAGE_NT_HEADERS *)(FileBuffer + DosHdr->e_lfanew);\r
1105   if (PeHdr->Signature != EFI_IMAGE_NT_SIGNATURE) {\r
1106     Error (NULL, 0, 0, InImageName, "PE header signature not found in source image");\r
1107     goto Finish;\r
1108   }\r
1109   \r
1110   if (OutImageType == FW_ACPI_IMAGE) {\r
1111     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ((UINT8 *) &(PeHdr->OptionalHeader) + PeHdr->FileHeader.SizeOfOptionalHeader); \r
1112     for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index ++, SectionHeader ++) {\r
1113       if (strcmp (SectionHeader->Name, ".data") == 0 || strcmp (SectionHeader->Name, ".sdata") == 0) {\r
1114         //\r
1115         // Check Acpi Table\r
1116         //\r
1117         if (SectionHeader->Misc.VirtualSize < SectionHeader->SizeOfRawData) {\r
1118           FileLength = SectionHeader->Misc.VirtualSize;\r
1119         } else {\r
1120           FileLength = SectionHeader->SizeOfRawData;\r
1121         }\r
1122 \r
1123         if (CheckAcpiTable (FileBuffer + SectionHeader->PointerToRawData, FileLength) != STATUS_SUCCESS) {\r
1124           Error (NULL, 0, 0, InImageName, "failed to check ACPI table");\r
1125           goto Finish;\r
1126         }\r
1127         \r
1128         //\r
1129         // Output Apci data to file\r
1130         //\r
1131         memcpy (FileBuffer, FileBuffer + SectionHeader->PointerToRawData, FileLength);\r
1132         FWriteFile (fpOut, FileBuffer, FileLength);\r
1133         fclose (fpOut);\r
1134         return STATUS_SUCCESS;\r
1135       }\r
1136     }\r
1137     Error (NULL, 0, 0, InImageName, "failed to get ACPI table");\r
1138     goto Finish;\r
1139   }\r
1140   //\r
1141   // Zero all unused fields of the DOS header\r
1142   //\r
1143   memcpy (&BackupDosHdr, DosHdr, sizeof (EFI_IMAGE_DOS_HEADER));\r
1144   memset (DosHdr, 0, sizeof (EFI_IMAGE_DOS_HEADER));\r
1145   DosHdr->e_magic  = BackupDosHdr.e_magic;\r
1146   DosHdr->e_lfanew = BackupDosHdr.e_lfanew;\r
1147 \r
1148   for (Index = sizeof (EFI_IMAGE_DOS_HEADER); Index < (UINT32 ) DosHdr->e_lfanew; Index++) {\r
1149     FileBuffer[Index] = DosHdr->e_cp;\r
1150   }\r
1151   \r
1152   //\r
1153   // Initialize TeImage Header\r
1154   //\r
1155   memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER));\r
1156   TEImageHeader.Signature        = EFI_TE_IMAGE_HEADER_SIGNATURE;\r
1157   TEImageHeader.Machine          = PeHdr->FileHeader.Machine;\r
1158   TEImageHeader.NumberOfSections = (UINT8) PeHdr->FileHeader.NumberOfSections;\r
1159   TEImageHeader.StrippedSize     = (UINT16) ((UINTN) ((UINT8 *) &(PeHdr->OptionalHeader) + PeHdr->FileHeader.SizeOfOptionalHeader) - (UINTN) FileBuffer);\r
1160   TEImageHeader.Subsystem        = (UINT8) Type;\r
1161 \r
1162   //\r
1163   // Patch the PE header\r
1164   //\r
1165   PeHdr->OptionalHeader.Subsystem = (UINT16) Type;\r
1166 \r
1167   if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
1168     Optional32 = (EFI_IMAGE_OPTIONAL_HEADER32 *)&PeHdr->OptionalHeader;\r
1169     Optional32->MajorLinkerVersion          = 0;\r
1170     Optional32->MinorLinkerVersion          = 0;\r
1171     Optional32->MajorOperatingSystemVersion = 0;\r
1172     Optional32->MinorOperatingSystemVersion = 0;\r
1173     Optional32->MajorImageVersion           = 0;\r
1174     Optional32->MinorImageVersion           = 0;\r
1175     Optional32->MajorSubsystemVersion       = 0;\r
1176     Optional32->MinorSubsystemVersion       = 0;\r
1177     Optional32->Win32VersionValue           = 0;\r
1178     Optional32->CheckSum                    = 0;\r
1179     Optional32->SizeOfStackReserve = 0;\r
1180     Optional32->SizeOfStackCommit  = 0;\r
1181     Optional32->SizeOfHeapReserve  = 0;\r
1182     Optional32->SizeOfHeapCommit   = 0;\r
1183     \r
1184     TEImageHeader.AddressOfEntryPoint = Optional32->AddressOfEntryPoint;\r
1185     TEImageHeader.BaseOfCode          = Optional32->BaseOfCode;\r
1186     TEImageHeader.ImageBase           = (UINT64) (Optional32->ImageBase);\r
1187 \r
1188     if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1189       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
1190       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
1191     }\r
1192 \r
1193     if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
1194       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
1195       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
1196     }\r
1197 \r
1198     //\r
1199     // Strip zero padding at the end of the .reloc section \r
1200     //\r
1201     if (Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1202       if (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) {\r
1203         SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1204         for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1205           //\r
1206           // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1207           //\r
1208           if (SectionHeader->VirtualAddress == Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {\r
1209             SectionHeader->Misc.VirtualSize = Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
1210             AllignedRelocSize = (Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional32->FileAlignment - 1) & (~(Optional32->FileAlignment - 1));\r
1211             //\r
1212             // Check to see if there is zero padding at the end of the base relocations\r
1213             //\r
1214             if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1215               //\r
1216               // Check to see if the base relocations are at the end of the file\r
1217               //\r
1218               if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional32->SizeOfImage) {\r
1219                 //\r
1220                 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1221                 //\r
1222                 Optional32->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1223                 Optional32->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1224                 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1225                 FileLength = Optional32->SizeOfImage;\r
1226               }\r
1227             }\r
1228           }\r
1229         }\r
1230       }\r
1231     }\r
1232   } \r
1233 \r
1234   if (PeHdr->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
1235     Optional64 = (EFI_IMAGE_OPTIONAL_HEADER64 *)&PeHdr->OptionalHeader;\r
1236     Optional64->MajorLinkerVersion          = 0;\r
1237     Optional64->MinorLinkerVersion          = 0;\r
1238     Optional64->MajorOperatingSystemVersion = 0;\r
1239     Optional64->MinorOperatingSystemVersion = 0;\r
1240     Optional64->MajorImageVersion           = 0;\r
1241     Optional64->MinorImageVersion           = 0;\r
1242     Optional64->MajorSubsystemVersion       = 0;\r
1243     Optional64->MinorSubsystemVersion       = 0;\r
1244     Optional64->Win32VersionValue           = 0;\r
1245     Optional64->CheckSum                    = 0;\r
1246     Optional64->SizeOfStackReserve = 0;\r
1247     Optional64->SizeOfStackCommit  = 0;\r
1248     Optional64->SizeOfHeapReserve  = 0;\r
1249     Optional64->SizeOfHeapCommit   = 0;\r
1250 \r
1251     TEImageHeader.AddressOfEntryPoint = Optional64->AddressOfEntryPoint;\r
1252     TEImageHeader.BaseOfCode          = Optional64->BaseOfCode;\r
1253     TEImageHeader.ImageBase           = (UINT64) (Optional64->ImageBase);\r
1254 \r
1255     if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {\r
1256       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress;\r
1257       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
1258     }\r
1259 \r
1260     if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
1261       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress;\r
1262       TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size;\r
1263     }\r
1264 \r
1265     //\r
1266     // Zero the .pdata section if the machine type is X64 and the Debug Directory is empty\r
1267     //\r
1268     if (PeHdr->FileHeader.Machine == IMAGE_FILE_MACHINE_X64) { // X64\r
1269       if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION) {\r
1270         if (Optional64->NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG && Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size == 0)) {\r
1271           SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1272           for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1273             if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress) {\r
1274               RuntimeFunction = (RUNTIME_FUNCTION *)(FileBuffer + SectionHeader->PointerToRawData);\r
1275               for (Index1 = 0; Index1 < Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size / sizeof (RUNTIME_FUNCTION); Index1++, RuntimeFunction++) {\r
1276                 SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1277                 for (Index2 = 0; Index2 < PeHdr->FileHeader.NumberOfSections; Index2++, SectionHeader++) {\r
1278                   if (RuntimeFunction->UnwindInfoAddress > SectionHeader->VirtualAddress && RuntimeFunction->UnwindInfoAddress < (SectionHeader->VirtualAddress + SectionHeader->SizeOfRawData)) {\r
1279                     UnwindInfo = (UNWIND_INFO *)(FileBuffer + SectionHeader->PointerToRawData + (RuntimeFunction->UnwindInfoAddress - SectionHeader->VirtualAddress));\r
1280                     if (UnwindInfo->Version == 1) {\r
1281                       memset (UnwindInfo + 1, 0, UnwindInfo->CountOfUnwindCodes * sizeof (UINT16));\r
1282                       memset (UnwindInfo, 0, sizeof (UNWIND_INFO));\r
1283                     }\r
1284                   }\r
1285                 }\r
1286                 memset (RuntimeFunction, 0, sizeof (RUNTIME_FUNCTION));\r
1287               }\r
1288 \r
1289               break;\r
1290             }\r
1291           }\r
1292           Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].Size = 0;\r
1293           Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_EXCEPTION].VirtualAddress = 0;\r
1294         }\r
1295       }\r
1296     }\r
1297 \r
1298     //\r
1299     // Strip zero padding at the end of the .reloc section \r
1300     //\r
1301     if (Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
1302       if (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) {\r
1303         SectionHeader = (EFI_IMAGE_SECTION_HEADER *)(FileBuffer + DosHdr->e_lfanew + sizeof(UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + PeHdr->FileHeader.SizeOfOptionalHeader);\r
1304         for (Index = 0; Index < PeHdr->FileHeader.NumberOfSections; Index++, SectionHeader++) {\r
1305           //\r
1306           // Look for the Section Header that starts as the same virtual address as the Base Relocation Data Directory\r
1307           //\r
1308           if (SectionHeader->VirtualAddress == Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) {\r
1309             SectionHeader->Misc.VirtualSize = Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size;\r
1310             AllignedRelocSize = (Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + Optional64->FileAlignment - 1) & (~(Optional64->FileAlignment - 1));\r
1311             //\r
1312             // Check to see if there is zero padding at the end of the base relocations\r
1313             //\r
1314             if (AllignedRelocSize < SectionHeader->SizeOfRawData) {\r
1315               //\r
1316               // Check to see if the base relocations are at the end of the file\r
1317               //\r
1318               if (SectionHeader->PointerToRawData + SectionHeader->SizeOfRawData == Optional64->SizeOfImage) {\r
1319                 //\r
1320                 // All the required conditions are met to strip the zero padding of the end of the base relocations section\r
1321                 //\r
1322                 Optional64->SizeOfImage -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1323                 Optional64->SizeOfInitializedData -= (SectionHeader->SizeOfRawData - AllignedRelocSize);\r
1324                 SectionHeader->SizeOfRawData = AllignedRelocSize;\r
1325                 FileLength = Optional64->SizeOfImage;\r
1326               }\r
1327             }\r
1328           }\r
1329         }\r
1330       }\r
1331     }\r
1332   }\r
1333 \r
1334   if (OutImageType == FW_TE_IMAGE) {\r
1335     if ((PeHdr->FileHeader.NumberOfSections &~0xFF) || (Type &~0xFF)) {\r
1336       //\r
1337       // Pack the subsystem and NumberOfSections into 1 byte. Make sure they fit both.\r
1338       //\r
1339       Error (NULL, 0, 0, InImageName, "image subsystem or NumberOfSections cannot be packed into 1 byte");\r
1340       goto Finish;\r
1341     }\r
1342 \r
1343     if ((PeHdr->OptionalHeader.SectionAlignment != PeHdr->OptionalHeader.FileAlignment)) {\r
1344       //\r
1345       // TeImage has the same section alignment and file alignment.\r
1346       //\r
1347       Error (NULL, 0, 0, InImageName, "Section-Alignment and File-Alignment does not match for TeImage");\r
1348       goto Finish;\r
1349     }\r
1350 \r
1351     //\r
1352     // Update Image to TeImage\r
1353     //\r
1354     FileLength = FileLength - TEImageHeader.StrippedSize;\r
1355     memcpy (FileBuffer + sizeof (EFI_TE_IMAGE_HEADER), FileBuffer + TEImageHeader.StrippedSize, FileLength);\r
1356     memcpy (FileBuffer, &TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER));\r
1357   }\r
1358 \r
1359   FWriteFile (fpOut, FileBuffer, FileLength);\r
1360   FileBuffer = NULL;\r
1361 \r
1362 Finish:\r
1363   if (FileBuffer != NULL) {\r
1364     free (FileBuffer);\r
1365   }\r
1366 \r
1367   if (fpOut != NULL) {\r
1368     //\r
1369     // Write converted data into fpOut file and close output file.\r
1370     //\r
1371     fclose (fpOut);\r
1372   }\r
1373   \r
1374   return GetUtilityStatus ();\r
1375 }\r