1 /** @file
2 *
3 *  Copyright (c) 2011 - 2015, 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 // This GUID is defined in the INGF file of ArmPkg/Application/LinuxLoader
18 CONST EFI_GUID mLinuxLoaderAppGuid = { 0x701f54f2, 0x0d70, 0x4b89, { 0xbc, 0x0a, 0xd9, 0xca, 0x25, 0x37, 0x90, 0x59 }};
19 
20 // Device path of the EFI Linux Loader in the Firmware Volume
21 EFI_DEVICE_PATH* mLinuxLoaderDevicePath = NULL;
22 
23 STATIC
24 BOOLEAN
HasFilePathEfiExtension(IN CHAR16 * FilePath)25 HasFilePathEfiExtension (
26   IN CHAR16* FilePath
27   )
28 {
29   return (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".EFI") == 0) ||
30          (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".efi") == 0);
31 }
32 
33 /**
34  * This function check if the DevicePath defines an EFI binary
35  *
36  * This function is used when the BDS support Linux loader to
37  * detect if the binary is an EFI application or potentially a
38  * Linux kernel.
39  */
40 EFI_STATUS
IsEfiBinary(IN EFI_DEVICE_PATH * DevicePath,OUT BOOLEAN * EfiBinary)41 IsEfiBinary (
42   IN  EFI_DEVICE_PATH* DevicePath,
43   OUT BOOLEAN          *EfiBinary
44   )
45 {
46   EFI_STATUS              Status;
47   CHAR16*                 FileName;
48   EFI_DEVICE_PATH*        PrevDevicePathNode;
49   EFI_DEVICE_PATH*        DevicePathNode;
50   EFI_PHYSICAL_ADDRESS    Image;
51   UINTN                   FileSize;
52   EFI_IMAGE_DOS_HEADER*   DosHeader;
53   UINTN                   PeCoffHeaderOffset;
54   EFI_IMAGE_NT_HEADERS32* NtHeader;
55 
56   ASSERT (EfiBinary != NULL);
57 
58   //
59   // Check if the last node of the device path is a FilePath node
60   //
61   PrevDevicePathNode = NULL;
62   DevicePathNode = DevicePath;
63   while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) {
64     PrevDevicePathNode = DevicePathNode;
65     DevicePathNode     = NextDevicePathNode (DevicePathNode);
66   }
67 
68   if ((PrevDevicePathNode != NULL) &&
69       (PrevDevicePathNode->Type == MEDIA_DEVICE_PATH) &&
70       (PrevDevicePathNode->SubType == MEDIA_FILEPATH_DP))
71   {
72     FileName = ((FILEPATH_DEVICE_PATH*)PrevDevicePathNode)->PathName;
73   } else {
74     FileName = NULL;
75   }
76 
77   if (FileName == NULL) {
78     Print (L"Is an EFI Application? ");
79     Status = GetHIInputBoolean (EfiBinary);
80     if (EFI_ERROR (Status)) {
81       return EFI_ABORTED;
82     }
83   } else if (HasFilePathEfiExtension (FileName)) {
84     *EfiBinary = TRUE;
85   } else {
86     // Check if the file exist
87     Status = BdsLoadImage (DevicePath, AllocateAnyPages, &Image, &FileSize);
88     if (!EFI_ERROR (Status)) {
89 
90       DosHeader = (EFI_IMAGE_DOS_HEADER *)(UINTN) Image;
91       if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
92         //
93         // DOS image header is present,
94         // so read the PE header after the DOS image header.
95         //
96         PeCoffHeaderOffset = DosHeader->e_lfanew;
97       } else {
98         PeCoffHeaderOffset = 0;
99       }
100 
101       //
102       // Check PE/COFF image.
103       //
104       NtHeader = (EFI_IMAGE_NT_HEADERS32 *)(UINTN) (Image + PeCoffHeaderOffset);
105       if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {
106         *EfiBinary = FALSE;
107       } else {
108         *EfiBinary = TRUE;
109       }
110 
111       // Free memory
112       gBS->FreePages (Image, EFI_SIZE_TO_PAGES (FileSize));
113     } else {
114       // If we did not manage to open it then ask for the type
115       Print (L"Is an EFI Application? ");
116       Status = GetHIInputBoolean (EfiBinary);
117       if (EFI_ERROR (Status)) {
118         return EFI_ABORTED;
119       }
120     }
121   }
122 
123   return EFI_SUCCESS;
124 }
125