summaryrefslogtreecommitdiff
path: root/ArmPlatformPkg/Bds/BootLinux.c
blob: 0445e894e153aade97fa02ff375da6fd610a0d73 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
/** @file
*
*  Copyright (c) 2011 - 2015, ARM Limited. All rights reserved.
*
*  This program and the accompanying materials
*  are licensed and made available under the terms and conditions of the BSD License
*  which accompanies this distribution.  The full text of the license may be found at
*  http://opensource.org/licenses/bsd-license.php
*
*  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
*  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
*
**/

#include "BdsInternal.h"

// This GUID is defined in the INGF file of ArmPkg/Application/LinuxLoader
CONST EFI_GUID mLinuxLoaderAppGuid = { 0x701f54f2, 0x0d70, 0x4b89, { 0xbc, 0x0a, 0xd9, 0xca, 0x25, 0x37, 0x90, 0x59 }};

// Device path of the EFI Linux Loader in the Firmware Volume
EFI_DEVICE_PATH* mLinuxLoaderDevicePath = NULL;

STATIC
BOOLEAN
HasFilePathEfiExtension (
  IN CHAR16* FilePath
  )
{
  return (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".EFI") == 0) ||
         (StrCmp (FilePath + (StrSize (FilePath) / sizeof (CHAR16)) - 5, L".efi") == 0);
}

/**
 * This function check if the DevicePath defines an EFI binary
 *
 * This function is used when the BDS support Linux loader to
 * detect if the binary is an EFI application or potentially a
 * Linux kernel.
 */
EFI_STATUS
IsEfiBinary (
  IN  EFI_DEVICE_PATH* DevicePath,
  OUT BOOLEAN          *EfiBinary
  )
{
  EFI_STATUS              Status;
  CHAR16*                 FileName;
  EFI_DEVICE_PATH*        PrevDevicePathNode;
  EFI_DEVICE_PATH*        DevicePathNode;
  EFI_PHYSICAL_ADDRESS    Image;
  UINTN                   FileSize;
  EFI_IMAGE_DOS_HEADER*   DosHeader;
  UINTN                   PeCoffHeaderOffset;
  EFI_IMAGE_NT_HEADERS32* NtHeader;

  ASSERT (EfiBinary != NULL);

  //
  // Check if the last node of the device path is a FilePath node
  //
  PrevDevicePathNode = NULL;
  DevicePathNode = DevicePath;
  while ((DevicePathNode != NULL) && !IsDevicePathEnd (DevicePathNode)) {
    PrevDevicePathNode = DevicePathNode;
    DevicePathNode     = NextDevicePathNode (DevicePathNode);
  }

  if ((PrevDevicePathNode != NULL) &&
      (PrevDevicePathNode->Type == MEDIA_DEVICE_PATH) &&
      (PrevDevicePathNode->SubType == MEDIA_FILEPATH_DP))
  {
    FileName = ((FILEPATH_DEVICE_PATH*)PrevDevicePathNode)->PathName;
  } else {
    FileName = NULL;
  }

  if (FileName == NULL) {
    Print (L"Is an EFI Application? ");
    Status = GetHIInputBoolean (EfiBinary);
    if (EFI_ERROR (Status)) {
      return EFI_ABORTED;
    }
  } else if (HasFilePathEfiExtension (FileName)) {
    *EfiBinary = TRUE;
  } else {
    // Check if the file exist
    Status = BdsLoadImage (DevicePath, AllocateAnyPages, &Image, &FileSize);
    if (!EFI_ERROR (Status)) {

      DosHeader = (EFI_IMAGE_DOS_HEADER *)(UINTN) Image;
      if (DosHeader->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
        //
        // DOS image header is present,
        // so read the PE header after the DOS image header.
        //
        PeCoffHeaderOffset = DosHeader->e_lfanew;
      } else {
        PeCoffHeaderOffset = 0;
      }

      //
      // Check PE/COFF image.
      //
      NtHeader = (EFI_IMAGE_NT_HEADERS32 *)(UINTN) (Image + PeCoffHeaderOffset);
      if (NtHeader->Signature != EFI_IMAGE_NT_SIGNATURE) {
        *EfiBinary = FALSE;
      } else {
        *EfiBinary = TRUE;
      }

      // Free memory
      gBS->FreePages (Image, EFI_SIZE_TO_PAGES (FileSize));
    } else {
      // If we did not manage to open it then ask for the type
      Print (L"Is an EFI Application? ");
      Status = GetHIInputBoolean (EfiBinary);
      if (EFI_ERROR (Status)) {
        return EFI_ABORTED;
      }
    }
  }

  return EFI_SUCCESS;
}