]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/BdsLib/BdsAppLoader.c
ArmPkg/BdsLib: Upgrade the library to use natively the Device Path
[mirror_edk2.git] / ArmPkg / Library / BdsLib / BdsAppLoader.c
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 }