Modified utility usage and version display.
[people/mcb30/edk2.git] / edk2 / Tools / CCode / Source / SecFixup / SecFixup.c
1 /*++\r
2 \r
3 Copyright (c)  1999-2006 Intel Corporation. All rights reserved\r
4 This program and the accompanying materials are licensed and made available \r
5 under the terms and conditions of the BSD License which accompanies this \r
6 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 \r
13 Module Name:\r
14 \r
15     SecFixup.c\r
16 \r
17 Abstract:\r
18 \r
19     This utility is part of build process for IA32 SEC FFS file.\r
20     \r
21     It fixup the reset vector data. The reset vector data binary file\r
22     will be wrapped as a RAW section and be located immediately after\r
23     the PE/TE section.\r
24 \r
25     The SEC EXE file can be either PE or TE file.\r
26     \r
27 --*/\r
28 \r
29 #include <stdio.h>\r
30 \r
31 #include <Common/UefiBaseTypes.h>\r
32 #include <Common/EfiImage.h>\r
33 #include <Common/FirmwareVolumeImageFormat.h>\r
34 \r
35 #include "EfiUtilityMsgs.c"\r
36 #include "SecFixup.h"\r
37 \r
38 VOID\r
39 Version (\r
40   VOID\r
41   )\r
42 /*++\r
43 \r
44 Routine Description:\r
45 \r
46   Displays the standard utility information to SDTOUT\r
47 \r
48 Arguments:\r
49 \r
50   None\r
51 \r
52 Returns:\r
53 \r
54   None\r
55 \r
56 --*/\r
57 {\r
58   printf ("%s v%d.%d -Tiano IA32 SEC Fixup Utility.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
59   printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");\r
60 }\r
61 \r
62 VOID\r
63 Usage (\r
64   VOID\r
65   )\r
66 /*++\r
67 \r
68 Routine Description:\r
69 \r
70   Displays the utility usage syntax to STDOUT\r
71 \r
72 Arguments:\r
73 \r
74   None\r
75 \r
76 Returns:\r
77 \r
78   None\r
79 \r
80 --*/\r
81 {\r
82   Version();\r
83   \r
84   printf ("\nUsage: %s SecExeFile ResetVectorDataFile OutputFile\n", UTILITY_NAME);\r
85   printf ("  Where:\n");\r
86   printf ("     SecExeFile           - Name of the IA32 SEC EXE file.\n");\r
87   printf ("     ResetVectorDataFile  - Name of the reset vector data binary file.\n");\r
88   printf ("     OutputFileName       - Name of the output file.\n");\r
89 }\r
90 \r
91 STATUS\r
92 main (\r
93   IN INTN   argc,\r
94   IN CHAR8  **argv\r
95   )\r
96 /*++\r
97 \r
98 Routine Description:\r
99 \r
100   Main function.\r
101 \r
102 Arguments:\r
103 \r
104   argc - Number of command line parameters.\r
105   argv - Array of pointers to parameter strings.\r
106 \r
107 Returns:\r
108   STATUS_SUCCESS - Utility exits successfully.\r
109   STATUS_ERROR   - Some error occurred during execution.\r
110 \r
111 --*/\r
112 {\r
113   FILE    *FpIn;\r
114 \r
115   FILE    *FpOut;\r
116   UINT32  AddressOfEntryPoint;\r
117   INT32   DestRel;\r
118   STATUS  Status;\r
119   UINT32  SecFileSize;\r
120 \r
121   SetUtilityName (UTILITY_NAME);\r
122 \r
123   if (argc == 1) {\r
124     Usage();\r
125     return STATUS_ERROR;\r
126   }\r
127     \r
128   if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0) ||\r
129       (strcmp(argv[1], "-?") == 0) || (strcmp(argv[1], "/?") == 0)) {\r
130     Usage();\r
131     return STATUS_ERROR;\r
132   }\r
133   \r
134   if ((strcmp(argv[1], "-V") == 0) || (strcmp(argv[1], "--version") == 0)) {\r
135     Version();\r
136     return STATUS_ERROR;\r
137   }\r
138   \r
139   //\r
140   // Verify the correct number of arguments\r
141   //\r
142   if (argc != MAX_ARGS) {\r
143     Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);\r
144     Usage ();\r
145     return STATUS_ERROR;\r
146   }\r
147   //\r
148   // Open the SEC exe file\r
149   //\r
150   if ((FpIn = fopen (argv[1], "rb")) == NULL) {\r
151     Error (NULL, 0, 0, "Unable to open file", argv[1]);\r
152     return STATUS_ERROR;\r
153   }\r
154   //\r
155   // Get the entry point of the EXE file\r
156   //\r
157   Status = GetEntryPoint (FpIn, &AddressOfEntryPoint);\r
158   if (Status != STATUS_SUCCESS) {\r
159     fclose (FpIn);\r
160     return STATUS_ERROR;\r
161   }\r
162   //\r
163   // Get the SEC file size\r
164   //\r
165   fseek (FpIn, 0, SEEK_END);\r
166   SecFileSize = ftell (FpIn);\r
167 \r
168   //\r
169   // Close the SEC file\r
170   //\r
171   fclose (FpIn);\r
172 \r
173   //\r
174   // Open the reset vector data file\r
175   //\r
176   if ((FpIn = fopen (argv[2], "rb")) == NULL) {\r
177     Error (NULL, 0, 0, "Unable to open file", argv[2]);\r
178     return STATUS_ERROR;\r
179   }\r
180   //\r
181   // Open the output file\r
182   //\r
183   if ((FpOut = fopen (argv[3], "w+b")) == NULL) {\r
184     Error (NULL, 0, 0, "Unable to open file", argv[3]);\r
185     fclose (FpIn);\r
186     return STATUS_ERROR;\r
187   }\r
188   //\r
189   // Copy the input file to the output file\r
190   //\r
191   if (CopyFile (FpIn, FpOut) != STATUS_SUCCESS) {\r
192     fclose (FpIn);\r
193     fclose (FpOut);\r
194     return STATUS_ERROR;\r
195   }\r
196   //\r
197   // Close the reset vector data file\r
198   //\r
199   fclose (FpIn);\r
200 \r
201   //\r
202   // Fix the destination relative in the jmp instruction\r
203   // in the reset vector data structure\r
204   //\r
205   fseek (FpOut, -DEST_REL_OFFSET, SEEK_END);\r
206   DestRel = AddressOfEntryPoint - (SecFileSize + sizeof (EFI_COMMON_SECTION_HEADER) + (UINT32) (ftell (FpOut)) + 2);\r
207   if (DestRel <= -65536) {\r
208     Error (NULL, 0, 0, "The SEC EXE file size is too big", NULL);\r
209     fclose (FpOut);\r
210     return STATUS_ERROR;\r
211   }\r
212 \r
213   if (fwrite (&DestRel, sizeof (UINT16), 1, FpOut) != 1) {\r
214     Error (NULL, 0, 0, "Failed to write to the output file", NULL);\r
215     fclose (FpOut);\r
216     return STATUS_ERROR;\r
217   }\r
218   //\r
219   // Close the output file\r
220   //\r
221   fclose (FpOut);\r
222 \r
223   return STATUS_SUCCESS;\r
224 }\r
225 \r
226 STATUS\r
227 GetEntryPoint (\r
228   IN  FILE   *ExeFile,\r
229   OUT UINT32 *EntryPoint\r
230   )\r
231 /*++\r
232 \r
233 Routine Description:\r
234 \r
235   Get the address of the entry point of a PE/TE file.\r
236 \r
237 Arguments:\r
238 \r
239   PeFile     - File pointer to the specified PE/TE file.\r
240   EntryPoint - Buffer for the address of the entry point to be returned.\r
241 \r
242 Returns:\r
243   STATUS_SUCCESS - Function completed successfully.\r
244   STATUS_ERROR   - Error occured.\r
245 \r
246 --*/\r
247 // GC_TODO:    ExeFile - add argument and description to function comment\r
248 {\r
249   EFI_IMAGE_DOS_HEADER    DosHeader;\r
250   EFI_IMAGE_NT_HEADERS32  NtHeader;\r
251   EFI_TE_IMAGE_HEADER     TeHeader;\r
252 \r
253   //\r
254   // Check if it is a TE file\r
255   //\r
256   fseek (ExeFile, 0, SEEK_SET);\r
257   //\r
258   // Attempt to read the TE header\r
259   //\r
260   if (fread (&TeHeader, sizeof (TeHeader), 1, ExeFile) == 1) {\r
261     if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
262       if (TeHeader.Machine != EFI_IMAGE_MACHINE_IA32) {\r
263         Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL);\r
264         return STATUS_ERROR;\r
265       }\r
266 \r
267       *EntryPoint = TeHeader.AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader.StrippedSize;\r
268       return STATUS_SUCCESS;\r
269     }\r
270   }\r
271   //\r
272   // Check if it is a PE file\r
273   //\r
274   fseek (ExeFile, 0, SEEK_SET);\r
275   //\r
276   // Attempt to read the DOS header\r
277   //\r
278   if (fread (&DosHeader, sizeof (DosHeader), 1, ExeFile) != 1) {\r
279     goto InvalidFile;\r
280   }\r
281   //\r
282   // Check the magic number\r
283   //\r
284   if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
285     goto InvalidFile;\r
286   }\r
287   //\r
288   // Position into the file and read the NT PE header\r
289   //\r
290   fseek (ExeFile, (long) DosHeader.e_lfanew, SEEK_SET);\r
291   if (fread (&NtHeader, sizeof (NtHeader), 1, ExeFile) != 1) {\r
292     goto InvalidFile;\r
293   }\r
294   //\r
295   // Check the PE signature in the header\r
296   //\r
297   if (NtHeader.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
298     goto InvalidFile;\r
299   }\r
300   //\r
301   // Make sure the PE file is PE32 for IA32\r
302   //\r
303   if (NtHeader.FileHeader.Machine != EFI_IMAGE_MACHINE_IA32 ||\r
304       NtHeader.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
305       ) {\r
306     Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL);\r
307     return STATUS_ERROR;\r
308   }\r
309   //\r
310   // Get the entry point from the optional header\r
311   //\r
312   *EntryPoint = NtHeader.OptionalHeader.AddressOfEntryPoint;\r
313   return STATUS_SUCCESS;\r
314 \r
315 InvalidFile:\r
316   Error (NULL, 0, 0, "The SEC file is neither PE nor TE file", NULL);\r
317   return STATUS_ERROR;\r
318 }\r
319 \r
320 STATUS\r
321 CopyFile (\r
322   FILE    *FpIn,\r
323   FILE    *FpOut\r
324   )\r
325 /*++\r
326 \r
327 Routine Description:\r
328 \r
329   Copy file.\r
330 \r
331 Arguments:\r
332 \r
333   FpIn  - File pointer to the source file.\r
334   FpOut - File pointer to the destination file.\r
335 \r
336 Returns:\r
337   STATUS_SUCCESS - Function completed successfully.\r
338   STATUS_ERROR   - Error occured.\r
339 \r
340 --*/\r
341 {\r
342   INTN  FileSize;\r
343 \r
344   INTN  Offset;\r
345 \r
346   INTN  Length;\r
347   UINT8 Buffer[BUF_SIZE];\r
348 \r
349   fseek (FpIn, 0, SEEK_END);\r
350   FileSize = ftell (FpIn);\r
351 \r
352   fseek (FpIn, 0, SEEK_SET);\r
353   fseek (FpOut, 0, SEEK_SET);\r
354 \r
355   Offset = 0;\r
356   while (Offset < FileSize) {\r
357     Length = sizeof (Buffer);\r
358     if (FileSize - Offset < Length) {\r
359       Length = FileSize - Offset;\r
360     }\r
361 \r
362     if (fread (Buffer, Length, 1, FpIn) != 1 || fwrite (Buffer, Length, 1, FpOut) != 1) {\r
363       Error (NULL, 0, 0, "Copy file error", NULL);\r
364       return STATUS_ERROR;\r
365     }\r
366 \r
367     Offset += Length;\r
368   }\r
369 \r
370   return STATUS_SUCCESS;\r
371 }\r