summaryrefslogtreecommitdiff
path: root/ArmPkg/Application/LinuxLoader/LinuxFdtLoader.c
blob: 8e5d1c6aa0f87743ff8a5d9f84c73b80f5f346b4 (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
/** @file
*
*  Copyright (c) 2011, 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 "LinuxInternal.h"

#include <Library/PrintLib.h>
#include <Library/UefiApplicationEntryPoint.h>

/**
  The user Entry Point for Application. The user code starts with this function
  as the real entry point for the application.

  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
  @param[in] SystemTable    A pointer to the EFI System Table.

  @retval EFI_SUCCESS       The entry point is executed successfully.
  @retval other             Some error occurs when executing this entry point.

**/
EFI_STATUS
EFIAPI
UefiMain (
  IN EFI_HANDLE        ImageHandle,
  IN EFI_SYSTEM_TABLE  *SystemTable
  )
{
  EFI_STATUS                   Status;
  EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage;
  LINUX_LOADER_OPTIONAL_DATA*  LinuxOptionalData;
  EFI_DEVICE_PATH*             DevicePathKernel;
  EFI_DEVICE_PATH*             InitrdDevicePath;
  CHAR16*                      OptionalDataInitrd;
  CHAR8*                       OptionalDataArguments;
  CHAR16*                      Initrd;

  Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **)&LoadedImage);
  ASSERT_EFI_ERROR (Status);

  if (LoadedImage->LoadOptionsSize == 0) {
    Status = LinuxLoaderConfig (LoadedImage);
  } else {
    // Ensure the signature is correct
    LinuxOptionalData = (LINUX_LOADER_OPTIONAL_DATA*)LoadedImage->LoadOptions;
    if (LinuxOptionalData->Signature != LINUX_LOADER_SIGNATURE) {
      return EFI_UNSUPPORTED;
    }

    // Generate the File Path Node for the Linux Kernel
    DevicePathKernel = FileDevicePath (LoadedImage->DeviceHandle, LINUX_KERNEL_NAME);

    if (LinuxOptionalData->CmdLineLength > 0) {
      OptionalDataArguments = (CHAR8*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
    } else {
      OptionalDataArguments = NULL;
    }

    if (LinuxOptionalData->InitrdPathListLength > 0) {
      if (OptionalDataArguments != NULL) {
        OptionalDataInitrd = (CHAR16*)(OptionalDataArguments + LinuxOptionalData->CmdLineLength);
      } else {
        OptionalDataInitrd = (CHAR16*)LinuxOptionalData + sizeof(LINUX_LOADER_OPTIONAL_DATA);
      }

      // If pointer not aligned
      if ((UINTN)OptionalDataInitrd & 0x1) {
        Initrd = (CHAR16*)AllocateCopyPool (LinuxOptionalData->InitrdPathListLength, OptionalDataInitrd);
      } else {
        Initrd = OptionalDataInitrd;
      }

      InitrdDevicePath = FileDevicePath (LoadedImage->DeviceHandle, Initrd);
    } else {
      OptionalDataInitrd = NULL;
      InitrdDevicePath   = NULL;
      Initrd             = NULL;
    }

    // Load and Start the Linux Kernel (we should never return)
    Status = BdsBootLinuxFdt (DevicePathKernel, InitrdDevicePath, OptionalDataArguments);

    if ((UINTN)OptionalDataInitrd & 0x1) {
      FreePool (Initrd);
    }

    FreePool (DevicePathKernel);
    if (InitrdDevicePath) {
      FreePool (InitrdDevicePath);
    }
  }

  return Status;
}