c2d46a1d5cb9cd3d74463f13d345ea34da54a355
[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 PrintUtilityInfo (\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 (\r
59     "%s - Tiano IA32 SEC Fixup Utility."" Version %i.%i\n\n",\r
60     UTILITY_NAME,\r
61     UTILITY_MAJOR_VERSION,\r
62     UTILITY_MINOR_VERSION\r
63     );\r
64 }\r
65 \r
66 VOID\r
67 PrintUsage (\r
68   VOID\r
69   )\r
70 /*++\r
71 \r
72 Routine Description:\r
73 \r
74   Displays the utility usage syntax to STDOUT\r
75 \r
76 Arguments:\r
77 \r
78   None\r
79 \r
80 Returns:\r
81 \r
82   None\r
83 \r
84 --*/\r
85 {\r
86   printf ("Usage: %s SecExeFile ResetVectorDataFile OutputFile\n", UTILITY_NAME);\r
87   printf ("  Where:\n");\r
88   printf ("\tSecExeFile           - Name of the IA32 SEC EXE file.\n");\r
89   printf ("\tResetVectorDataFile  - Name of the reset vector data binary file.\n");\r
90   printf ("\tOutputFileName       - Name of the output file.\n\n");\r
91 }\r
92 \r
93 STATUS\r
94 main (\r
95   IN INTN   argc,\r
96   IN CHAR8  **argv\r
97   )\r
98 /*++\r
99 \r
100 Routine Description:\r
101 \r
102   Main function.\r
103 \r
104 Arguments:\r
105 \r
106   argc - Number of command line parameters.\r
107   argv - Array of pointers to parameter strings.\r
108 \r
109 Returns:\r
110   STATUS_SUCCESS - Utility exits successfully.\r
111   STATUS_ERROR   - Some error occurred during execution.\r
112 \r
113 --*/\r
114 {\r
115   FILE    *FpIn;\r
116 \r
117   FILE    *FpOut;\r
118   UINT32  AddressOfEntryPoint;\r
119   INT32   DestRel;\r
120   STATUS  Status;\r
121   UINT32  SecFileSize;\r
122 \r
123   SetUtilityName (UTILITY_NAME);\r
124 \r
125   //\r
126   // Display utility information\r
127   //\r
128   PrintUtilityInfo ();\r
129 \r
130   //\r
131   // Verify the correct number of arguments\r
132   //\r
133   if (argc != MAX_ARGS) {\r
134     Error (NULL, 0, 0, "invalid number of input parameters specified", NULL);\r
135     PrintUsage ();\r
136     return STATUS_ERROR;\r
137   }\r
138   //\r
139   // Open the SEC exe file\r
140   //\r
141   if ((FpIn = fopen (argv[1], "rb")) == NULL) {\r
142     Error (NULL, 0, 0, "Unable to open file", argv[1]);\r
143     return STATUS_ERROR;\r
144   }\r
145   //\r
146   // Get the entry point of the EXE file\r
147   //\r
148   Status = GetEntryPoint (FpIn, &AddressOfEntryPoint);\r
149   if (Status != STATUS_SUCCESS) {\r
150     fclose (FpIn);\r
151     return STATUS_ERROR;\r
152   }\r
153   //\r
154   // Get the SEC file size\r
155   //\r
156   fseek (FpIn, 0, SEEK_END);\r
157   SecFileSize = ftell (FpIn);\r
158 \r
159   //\r
160   // Close the SEC file\r
161   //\r
162   fclose (FpIn);\r
163 \r
164   //\r
165   // Open the reset vector data file\r
166   //\r
167   if ((FpIn = fopen (argv[2], "rb")) == NULL) {\r
168     Error (NULL, 0, 0, "Unable to open file", argv[2]);\r
169     return STATUS_ERROR;\r
170   }\r
171   //\r
172   // Open the output file\r
173   //\r
174   if ((FpOut = fopen (argv[3], "w+b")) == NULL) {\r
175     Error (NULL, 0, 0, "Unable to open file", argv[3]);\r
176     fclose (FpIn);\r
177     return STATUS_ERROR;\r
178   }\r
179   //\r
180   // Copy the input file to the output file\r
181   //\r
182   if (CopyFile (FpIn, FpOut) != STATUS_SUCCESS) {\r
183     fclose (FpIn);\r
184     fclose (FpOut);\r
185     return STATUS_ERROR;\r
186   }\r
187   //\r
188   // Close the reset vector data file\r
189   //\r
190   fclose (FpIn);\r
191 \r
192   //\r
193   // Fix the destination relative in the jmp instruction\r
194   // in the reset vector data structure\r
195   //\r
196   fseek (FpOut, -DEST_REL_OFFSET, SEEK_END);\r
197   DestRel = AddressOfEntryPoint - (SecFileSize + sizeof (EFI_COMMON_SECTION_HEADER) + (UINT32) (ftell (FpOut)) + 2);\r
198   if (DestRel <= -65536) {\r
199     Error (NULL, 0, 0, "The SEC EXE file size is too big", NULL);\r
200     fclose (FpOut);\r
201     return STATUS_ERROR;\r
202   }\r
203 \r
204   if (fwrite (&DestRel, sizeof (UINT16), 1, FpOut) != 1) {\r
205     Error (NULL, 0, 0, "Failed to write to the output file", NULL);\r
206     fclose (FpOut);\r
207     return STATUS_ERROR;\r
208   }\r
209   //\r
210   // Close the output file\r
211   //\r
212   fclose (FpOut);\r
213 \r
214   return STATUS_SUCCESS;\r
215 }\r
216 \r
217 STATUS\r
218 GetEntryPoint (\r
219   IN  FILE   *ExeFile,\r
220   OUT UINT32 *EntryPoint\r
221   )\r
222 /*++\r
223 \r
224 Routine Description:\r
225 \r
226   Get the address of the entry point of a PE/TE file.\r
227 \r
228 Arguments:\r
229 \r
230   PeFile     - File pointer to the specified PE/TE file.\r
231   EntryPoint - Buffer for the address of the entry point to be returned.\r
232 \r
233 Returns:\r
234   STATUS_SUCCESS - Function completed successfully.\r
235   STATUS_ERROR   - Error occured.\r
236 \r
237 --*/\r
238 // GC_TODO:    ExeFile - add argument and description to function comment\r
239 {\r
240   EFI_IMAGE_DOS_HEADER    DosHeader;\r
241   EFI_IMAGE_NT_HEADERS32  NtHeader;\r
242   EFI_TE_IMAGE_HEADER     TeHeader;\r
243 \r
244   //\r
245   // Check if it is a TE file\r
246   //\r
247   fseek (ExeFile, 0, SEEK_SET);\r
248   //\r
249   // Attempt to read the TE header\r
250   //\r
251   if (fread (&TeHeader, sizeof (TeHeader), 1, ExeFile) == 1) {\r
252     if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
253       if (TeHeader.Machine != EFI_IMAGE_MACHINE_IA32) {\r
254         Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL);\r
255         return STATUS_ERROR;\r
256       }\r
257 \r
258       *EntryPoint = TeHeader.AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader.StrippedSize;\r
259       return STATUS_SUCCESS;\r
260     }\r
261   }\r
262   //\r
263   // Check if it is a PE file\r
264   //\r
265   fseek (ExeFile, 0, SEEK_SET);\r
266   //\r
267   // Attempt to read the DOS header\r
268   //\r
269   if (fread (&DosHeader, sizeof (DosHeader), 1, ExeFile) != 1) {\r
270     goto InvalidFile;\r
271   }\r
272   //\r
273   // Check the magic number\r
274   //\r
275   if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) {\r
276     goto InvalidFile;\r
277   }\r
278   //\r
279   // Position into the file and read the NT PE header\r
280   //\r
281   fseek (ExeFile, (long) DosHeader.e_lfanew, SEEK_SET);\r
282   if (fread (&NtHeader, sizeof (NtHeader), 1, ExeFile) != 1) {\r
283     goto InvalidFile;\r
284   }\r
285   //\r
286   // Check the PE signature in the header\r
287   //\r
288   if (NtHeader.Signature != EFI_IMAGE_NT_SIGNATURE) {\r
289     goto InvalidFile;\r
290   }\r
291   //\r
292   // Make sure the PE file is PE32 for IA32\r
293   //\r
294   if (NtHeader.FileHeader.Machine != EFI_IMAGE_MACHINE_IA32 ||\r
295       NtHeader.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
296       ) {\r
297     Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL);\r
298     return STATUS_ERROR;\r
299   }\r
300   //\r
301   // Get the entry point from the optional header\r
302   //\r
303   *EntryPoint = NtHeader.OptionalHeader.AddressOfEntryPoint;\r
304   return STATUS_SUCCESS;\r
305 \r
306 InvalidFile:\r
307   Error (NULL, 0, 0, "The SEC file is neither PE nor TE file", NULL);\r
308   return STATUS_ERROR;\r
309 }\r
310 \r
311 STATUS\r
312 CopyFile (\r
313   FILE    *FpIn,\r
314   FILE    *FpOut\r
315   )\r
316 /*++\r
317 \r
318 Routine Description:\r
319 \r
320   Copy file.\r
321 \r
322 Arguments:\r
323 \r
324   FpIn  - File pointer to the source file.\r
325   FpOut - File pointer to the destination file.\r
326 \r
327 Returns:\r
328   STATUS_SUCCESS - Function completed successfully.\r
329   STATUS_ERROR   - Error occured.\r
330 \r
331 --*/\r
332 {\r
333   INTN  FileSize;\r
334 \r
335   INTN  Offset;\r
336 \r
337   INTN  Length;\r
338   UINT8 Buffer[BUF_SIZE];\r
339 \r
340   fseek (FpIn, 0, SEEK_END);\r
341   FileSize = ftell (FpIn);\r
342 \r
343   fseek (FpIn, 0, SEEK_SET);\r
344   fseek (FpOut, 0, SEEK_SET);\r
345 \r
346   Offset = 0;\r
347   while (Offset < FileSize) {\r
348     Length = sizeof (Buffer);\r
349     if (FileSize - Offset < Length) {\r
350       Length = FileSize - Offset;\r
351     }\r
352 \r
353     if (fread (Buffer, Length, 1, FpIn) != 1 || fwrite (Buffer, Length, 1, FpOut) != 1) {\r
354       Error (NULL, 0, 0, "Copy file error", NULL);\r
355       return STATUS_ERROR;\r
356     }\r
357 \r
358     Offset += Length;\r
359   }\r
360 \r
361   return STATUS_SUCCESS;\r
362 }\r