Initial import.
[mirror_edk2.git] / EdkModulePkg / Core / Pei / Image / Image.c
CommitLineData
878ddf1f 1/*++\r
2\r
3Copyright (c) 2006, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 Image.c\r
15\r
16Abstract:\r
17\r
18 Pei Core Load Image Support\r
19\r
20--*/\r
21\r
22#include <PeiMain.h>\r
23\r
24EFI_STATUS\r
25PeiLoadImage (\r
26 IN EFI_PEI_SERVICES **PeiServices,\r
27 IN EFI_FFS_FILE_HEADER *PeimFileHeader,\r
28 OUT VOID **EntryPoint\r
29 )\r
30/*++\r
31\r
32Routine Description:\r
33\r
34 Routine for loading file image.\r
35\r
36Arguments:\r
37\r
38 PeiServices - The PEI core services table.\r
39 PeimFileHeader - Pointer to the FFS file header of the image.\r
40 EntryPoint - Pointer to entry point of specified image file for output.\r
41\r
42Returns:\r
43\r
44 Status - EFI_SUCCESS - Image is successfully loaded.\r
45 EFI_NOT_FOUND - Fail to locate necessary PPI\r
46 Others - Fail to load file.\r
47\r
48--*/\r
49{\r
50 EFI_STATUS Status;\r
51 VOID *Pe32Data;\r
52 EFI_PEI_FV_FILE_LOADER_PPI *FvLoadFilePpi;\r
53//#ifdef EFI_NT_EMULATOR\r
54// EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor;\r
55// NT_PEI_LOAD_FILE_PPI *PeiNtService;\r
56//#endif\r
57 EFI_PHYSICAL_ADDRESS ImageAddress;\r
58 UINT64 ImageSize;\r
59 EFI_PHYSICAL_ADDRESS ImageEntryPoint;\r
60 EFI_TE_IMAGE_HEADER *TEImageHeader;\r
61\r
62 *EntryPoint = NULL;\r
63 TEImageHeader = NULL;\r
64\r
65 //\r
66 // Try to find a PE32 section.\r
67 //\r
68 Status = PeiCoreFfsFindSectionData (\r
69 EFI_SECTION_PE32,\r
70 PeimFileHeader,\r
71 &Pe32Data\r
72 );\r
73 //\r
74 // If we didn't find a PE32 section, try to find a TE section.\r
75 //\r
76 if (EFI_ERROR (Status)) {\r
77 Status = PeiCoreFfsFindSectionData (\r
78 EFI_SECTION_TE,\r
79 PeimFileHeader,\r
80 (VOID **) &TEImageHeader\r
81 );\r
82 if (EFI_ERROR (Status) || TEImageHeader == NULL) {\r
83 //\r
84 // There was not a PE32 or a TE section, so assume that it's a Compressed section\r
85 // and use the LoadFile\r
86 //\r
87 Status = PeiCoreLocatePpi (\r
88 &gEfiPeiFvFileLoaderPpiGuid,\r
89 0,\r
90 NULL,\r
91 (VOID **)&FvLoadFilePpi\r
92 );\r
93 if (EFI_ERROR (Status)) {\r
94 return EFI_NOT_FOUND;\r
95 }\r
96\r
97 Status = FvLoadFilePpi->FvLoadFile (\r
98 FvLoadFilePpi,\r
99 PeimFileHeader,\r
100 &ImageAddress,\r
101 &ImageSize,\r
102 &ImageEntryPoint\r
103 );\r
104\r
105 if (EFI_ERROR (Status)) {\r
106 return EFI_NOT_FOUND;\r
107 }\r
108\r
109 //\r
110 // Retrieve the entry point from the PE/COFF image header\r
111 //\r
112 Status = PeCoffLoaderGetEntryPoint ((VOID *)(UINTN)ImageAddress, EntryPoint);\r
113 if (EFI_ERROR (Status)) {\r
114 return EFI_NOT_FOUND;\r
115 }\r
116 } else {\r
117 //\r
118 // Retrieve the entry point from the TE image header\r
119 //\r
120 ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) TEImageHeader;\r
121 *EntryPoint = (VOID *)((UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) +\r
122 TEImageHeader->AddressOfEntryPoint - TEImageHeader->StrippedSize);\r
123 }\r
124 } else {\r
125 //\r
126 // Retrieve the entry point from the PE/COFF image header\r
127 //\r
128 ImageAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Pe32Data;\r
129 Status = PeCoffLoaderGetEntryPoint (Pe32Data, EntryPoint);\r
130 if (EFI_ERROR (Status)) {\r
131 return EFI_NOT_FOUND;\r
132 }\r
133 }\r
134\r
135 //\r
136 // Print debug message: Loading PEIM at 0x12345678 EntryPoint=0x12345688 Driver.efi\r
137 //\r
138 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "Loading PEIM at 0x%08x EntryPoint=0x%08x ", Pe32Data, *EntryPoint));\r
139 DEBUG_CODE (\r
140 EFI_IMAGE_DATA_DIRECTORY * DirectoryEntry;\r
141 EFI_IMAGE_DEBUG_DIRECTORY_ENTRY * DebugEntry;\r
142 UINTN DirCount;\r
143 UINTN Index;\r
144 UINTN Index1;\r
145 BOOLEAN FileNameFound;\r
146 CHAR8 *AsciiString;\r
147 CHAR8 AsciiBuffer[512];\r
148 VOID *CodeViewEntryPointer;\r
149 INTN TEImageAdjust;\r
150 EFI_IMAGE_DOS_HEADER *DosHeader;\r
151 EFI_IMAGE_NT_HEADERS *PeHeader;\r
152\r
153 DosHeader = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
154 if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
155 //\r
156 // DOS image header is present, so read the PE header after the DOS image header\r
157 //\r
158 PeHeader = (EFI_IMAGE_NT_HEADERS *) ((UINTN) Pe32Data + (UINTN) ((DosHeader->e_lfanew) & 0x0ffff));\r
159 } else {\r
160 //\r
161 // DOS image header is not present, so PE header is at the image base\r
162 //\r
163 PeHeader = (EFI_IMAGE_NT_HEADERS *) Pe32Data;\r
164 }\r
165\r
166 //\r
167 // Find the codeview info in the image and display the file name\r
168 // being loaded.\r
169 //\r
170 // Per the PE/COFF spec, you can't assume that a given data directory\r
171 // is present in the image. You have to check the NumberOfRvaAndSizes in\r
172 // the optional header to verify a desired directory entry is there.\r
173 //\r
174 DebugEntry = NULL;\r
175 DirectoryEntry = NULL;\r
176 TEImageAdjust = 0;\r
177 if (TEImageHeader == NULL) {\r
178 if (PeHeader->OptionalHeader.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
179 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(PeHeader->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
180 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) ImageAddress + DirectoryEntry->VirtualAddress);\r
181 }\r
182 } else {\r
183 if (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
184 DirectoryEntry = &TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
185 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize;\r
186 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) TEImageHeader +\r
187 TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
188 TEImageAdjust);\r
189 }\r
190 }\r
191\r
192 if (DebugEntry != NULL && DirectoryEntry != NULL) {\r
193 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount++, DebugEntry++) {\r
194 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
195 if (DebugEntry->SizeOfData > 0) {\r
196 CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageAddress + (UINTN)TEImageAdjust);\r
197 switch (* (UINT32 *) CodeViewEntryPointer) {\r
198 case CODEVIEW_SIGNATURE_NB10:\r
199 AsciiString = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);\r
200 break;\r
201\r
202 case CODEVIEW_SIGNATURE_RSDS:\r
203 AsciiString = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);\r
204 break;\r
205\r
206 default:\r
207 AsciiString = NULL;\r
208 break;\r
209 }\r
210 if (AsciiString != NULL) {\r
211 FileNameFound = FALSE;\r
212 for (Index = 0, Index1 = 0; AsciiString[Index] != 0; Index++) {\r
213 if (AsciiString[Index] == '\\') {\r
214 Index1 = Index;\r
215 FileNameFound = TRUE;\r
216 }\r
217 }\r
218\r
219 if (FileNameFound) {\r
220 for (Index = Index1 + 1; AsciiString[Index] != '.'; Index++) {\r
221 AsciiBuffer[Index - (Index1 + 1)] = AsciiString[Index];\r
222 }\r
223 AsciiBuffer[Index - (Index1 + 1)] = 0;\r
224 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "%a.efi", AsciiBuffer));\r
225 break;\r
226 }\r
227 }\r
228 }\r
229 }\r
230 }\r
231 }\r
232 );\r
233\r
234 DEBUG ((EFI_D_INFO | EFI_D_LOAD, "\n"));\r
235\r
236 return EFI_SUCCESS;\r
237}\r