]>
Commit | Line | Data |
---|---|---|
a355a365 | 1 | /** @file |
2 | * | |
3 | * Copyright (c) 2011, ARM Limited. All rights reserved. | |
4 | * | |
5 | * This program and the accompanying materials | |
6 | * are licensed and made available under the terms and conditions of the BSD License | |
7 | * which accompanies this distribution. The full text of the license may be found at | |
8 | * http://opensource.org/licenses/bsd-license.php | |
9 | * | |
10 | * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
11 | * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
12 | * | |
13 | **/ | |
14 | ||
15 | #include "BdsInternal.h" | |
16 | ||
17 | //#include <Library/PeCoffLib.h> | |
18 | #include <Library/DxeServicesLib.h> | |
19 | ||
20 | //TODO: RemoveMe | |
21 | #include <Protocol/DevicePathToText.h> | |
22 | ||
23 | /** | |
24 | Retrieves the magic value from the PE/COFF header. | |
25 | ||
26 | @param Hdr The buffer in which to return the PE32, PE32+, or TE header. | |
27 | ||
28 | @return EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC - Image is PE32 | |
29 | @return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC - Image is PE32+ | |
30 | ||
31 | **/ | |
32 | UINT16 | |
33 | PeCoffLoaderGetPeHeaderMagicValue ( | |
34 | IN EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr | |
35 | ) | |
36 | { | |
37 | // | |
38 | // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value | |
39 | // in the PE/COFF Header. If the MachineType is Itanium(IA64) and the | |
40 | // Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC | |
41 | // then override the returned value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC | |
42 | // | |
43 | if (Hdr.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { | |
44 | return EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; | |
45 | } | |
46 | // | |
47 | // Return the magic value from the PC/COFF Optional Header | |
48 | // | |
49 | return Hdr.Pe32->OptionalHeader.Magic; | |
50 | } | |
51 | ||
52 | STATIC | |
53 | BOOLEAN | |
54 | IsLoadableImage ( | |
55 | VOID* Image | |
56 | ) | |
57 | { | |
58 | UINT16 Magic; | |
59 | EFI_IMAGE_DOS_HEADER *DosHeader; | |
60 | EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Header; | |
61 | ||
62 | if (Image == NULL) { | |
63 | return FALSE; | |
64 | } | |
65 | ||
66 | DosHeader = (EFI_IMAGE_DOS_HEADER*)Image; | |
67 | if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) { | |
68 | Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)((UINT8*)Image + DosHeader->e_lfanew); | |
69 | } else { | |
70 | Header.Pe32 = (EFI_IMAGE_NT_HEADERS32*)(Image); | |
71 | } | |
72 | ||
73 | if (Header.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { | |
74 | // It is a TE Image | |
75 | return TRUE; | |
76 | } else if (Header.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { | |
77 | Magic = PeCoffLoaderGetPeHeaderMagicValue (Header); | |
78 | if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { | |
79 | // It is a PE32 Image | |
80 | return TRUE; | |
81 | } else if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { | |
82 | // It is a PE32+ Image | |
83 | return TRUE; | |
84 | } else { | |
85 | DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognized PE Image\n")); | |
86 | } | |
87 | } else { | |
88 | DEBUG ((EFI_D_ERROR,"BdsLoadBinaryFromPath(): Fail unrecognize image\n")); | |
89 | } | |
90 | ||
91 | return FALSE; | |
92 | } | |
93 | ||
94 | STATIC | |
95 | EFI_STATUS | |
96 | BdsLoadFileFromFirmwareVolume ( | |
97 | IN EFI_HANDLE FvHandle, | |
98 | IN CHAR16 *FilePath, | |
99 | IN EFI_FV_FILETYPE FileTypeFilter, | |
100 | OUT EFI_DEVICE_PATH **EfiAppDevicePath | |
101 | ) | |
102 | { | |
103 | EFI_FIRMWARE_VOLUME2_PROTOCOL *FvProtocol; | |
104 | VOID *Key; | |
105 | EFI_STATUS Status, FileStatus; | |
106 | EFI_GUID NameGuid; | |
107 | EFI_FV_FILETYPE FileType; | |
108 | EFI_FV_FILE_ATTRIBUTES Attributes; | |
109 | UINTN Size; | |
110 | UINTN UiStringLen; | |
111 | CHAR16 *UiSection; | |
112 | UINT32 Authentication; | |
113 | EFI_DEVICE_PATH *FvDevicePath; | |
114 | MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FileDevicePath; | |
115 | ||
116 | Status = gBS->HandleProtocol (FvHandle,&gEfiFirmwareVolume2ProtocolGuid, (VOID **)&FvProtocol); | |
117 | if (EFI_ERROR(Status)) { | |
118 | return Status; | |
119 | } | |
120 | ||
121 | // Length of FilePath | |
122 | UiStringLen = StrLen (FilePath); | |
123 | ||
124 | // Allocate Key | |
125 | Key = AllocatePool (FvProtocol->KeySize); | |
126 | ASSERT (Key != NULL); | |
127 | ZeroMem (Key, FvProtocol->KeySize); | |
128 | ||
129 | do { | |
130 | // Search in all files | |
131 | FileType = FileTypeFilter; | |
132 | ||
133 | Status = FvProtocol->GetNextFile (FvProtocol, Key, &FileType, &NameGuid, &Attributes, &Size); | |
134 | if (!EFI_ERROR (Status)) { | |
135 | UiSection = NULL; | |
136 | FileStatus = FvProtocol->ReadSection ( | |
137 | FvProtocol, | |
138 | &NameGuid, | |
139 | EFI_SECTION_USER_INTERFACE, | |
140 | 0, | |
141 | (VOID **)&UiSection, | |
142 | &Size, | |
143 | &Authentication | |
144 | ); | |
145 | if (!EFI_ERROR (FileStatus)) { | |
146 | if (StrnCmp (FilePath, UiSection, UiStringLen) == 0) { | |
147 | // | |
148 | // We found a UiString match. | |
149 | // | |
150 | Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath); | |
151 | ||
152 | // Generate the Device Path for the file | |
153 | //DevicePath = DuplicateDevicePath(FvDevicePath); | |
154 | EfiInitializeFwVolDevicepathNode (&FileDevicePath, &NameGuid); | |
155 | *EfiAppDevicePath = AppendDevicePathNode (FvDevicePath, (EFI_DEVICE_PATH_PROTOCOL *)&FileDevicePath); | |
156 | ||
157 | FreePool (Key); | |
158 | FreePool (UiSection); | |
159 | return FileStatus; | |
160 | } | |
161 | FreePool (UiSection); | |
162 | } | |
163 | } | |
164 | } while (!EFI_ERROR (Status)); | |
165 | ||
166 | FreePool(Key); | |
167 | return Status; | |
168 | } | |
169 | ||
170 | /** | |
171 | Start an EFI Application from any Firmware Volume | |
172 | ||
173 | @param EfiApp EFI Application Name | |
174 | ||
175 | @retval EFI_SUCCESS All drivers have been connected | |
176 | @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found | |
177 | @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results. | |
178 | ||
179 | **/ | |
180 | EFI_STATUS | |
181 | BdsLoadApplication ( | |
182 | IN EFI_HANDLE ParentImageHandle, | |
183 | IN CHAR16* EfiApp | |
184 | ) | |
185 | { | |
186 | EFI_STATUS Status; | |
187 | UINTN NoHandles, HandleIndex; | |
188 | EFI_HANDLE *Handles; | |
189 | EFI_DEVICE_PATH *FvDevicePath; | |
190 | EFI_DEVICE_PATH *EfiAppDevicePath; | |
191 | ||
192 | // Need to connect every drivers to ensure no dependencies are missing for the application | |
193 | Status = BdsConnectAllDrivers(); | |
194 | if (EFI_ERROR(Status)) { | |
195 | DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n")); | |
196 | return Status; | |
197 | } | |
198 | ||
199 | // Search the application in any Firmware Volume | |
200 | Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiFirmwareVolume2ProtocolGuid, NULL, &NoHandles, &Handles); | |
201 | if (EFI_ERROR (Status) || (NoHandles == 0)) { | |
202 | DEBUG ((EFI_D_ERROR, "FAIL to find Firmware Volume\n")); | |
203 | return Status; | |
204 | } | |
205 | ||
206 | // Search in all Firmware Volume for the EFI Application | |
207 | for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) { | |
208 | Status = BdsLoadFileFromFirmwareVolume (Handles[HandleIndex], EfiApp, EFI_FV_FILETYPE_APPLICATION, &EfiAppDevicePath); | |
209 | if (!EFI_ERROR (Status)) { | |
210 | // Start the application | |
211 | Status = BdsStartEfiApplication (ParentImageHandle, EfiAppDevicePath); | |
212 | return Status; | |
213 | } | |
214 | } | |
215 | ||
216 | return Status; | |
217 | } |