Home | History | Annotate | Download | only in Arm
      1 /** @file
      2 
      3   Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
      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 "AndroidFastbootApp.h"
     16 
     17 #include <Protocol/DevicePath.h>
     18 
     19 #include <Library/BaseMemoryLib.h>
     20 #include <Library/BdsLib.h>
     21 #include <Library/DevicePathLib.h>
     22 #include <Library/PrintLib.h>
     23 #include <Library/UefiBootServicesTableLib.h>
     24 #include <Library/UefiRuntimeServicesTableLib.h>
     25 #include <Library/UefiLib.h>
     26 
     27 #define LINUX_LOADER_COMMAND_LINE       L"%s -f %s -c %s"
     28 
     29 // This GUID is defined in the INGF file of ArmPkg/Application/LinuxLoader
     30 CONST EFI_GUID mLinuxLoaderAppGuid = { 0x701f54f2, 0x0d70, 0x4b89, { 0xbc, 0x0a, 0xd9, 0xca, 0x25, 0x37, 0x90, 0x59 }};
     31 
     32 // Device Path representing an image in memory
     33 #pragma pack(1)
     34 typedef struct {
     35   MEMMAP_DEVICE_PATH                      Node1;
     36   EFI_DEVICE_PATH_PROTOCOL                End;
     37 } MEMORY_DEVICE_PATH;
     38 #pragma pack()
     39 
     40 STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate =
     41 {
     42   {
     43     {
     44       HARDWARE_DEVICE_PATH,
     45       HW_MEMMAP_DP,
     46       {
     47         (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
     48         (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
     49       },
     50     }, // Header
     51     0, // StartingAddress (set at runtime)
     52     0  // EndingAddress   (set at runtime)
     53   }, // Node1
     54   {
     55     END_DEVICE_PATH_TYPE,
     56     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     57     { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
     58   } // End
     59 };
     60 
     61 #define KERNEL_IMAGE_STEXT_OFFSET     0x12C
     62 #define KERNEL_IMAGE_RAW_SIZE_OFFSET  0x130
     63 
     64 EFI_STATUS
     65 BootAndroidBootImg (
     66   IN UINTN    BufferSize,
     67   IN VOID    *Buffer
     68   )
     69 {
     70   EFI_STATUS                          Status;
     71   CHAR8                               KernelArgs[BOOTIMG_KERNEL_ARGS_SIZE];
     72   VOID                               *Kernel;
     73   UINTN                               KernelSize;
     74   VOID                               *Ramdisk;
     75   UINTN                               RamdiskSize;
     76   MEMORY_DEVICE_PATH                  KernelDevicePath;
     77   MEMORY_DEVICE_PATH*                 RamdiskDevicePath;
     78   EFI_PHYSICAL_ADDRESS                FdtBase;
     79   CHAR16                              UnicodeArgs[BOOTIMG_KERNEL_ARGS_SIZE];
     80   CHAR16                              InitrdArgs[64];
     81   BDS_LOAD_OPTION                    *BdsLoadOptions;
     82   UINTN                               VariableSize;
     83   CHAR16                              SerialNoArgs[40], DataUnicode[17];
     84 
     85   Status = ParseAndroidBootImg (
     86             Buffer,
     87             &Kernel,
     88             &KernelSize,
     89             &Ramdisk,
     90             &RamdiskSize,
     91             KernelArgs
     92             );
     93   if (EFI_ERROR (Status)) {
     94     return Status;
     95   }
     96 
     97   KernelDevicePath = MemoryDevicePathTemplate;
     98 
     99   KernelSize = *(UINT32 *)(Kernel + KERNEL_IMAGE_STEXT_OFFSET) +
    100                *(UINT32 *)(Kernel + KERNEL_IMAGE_RAW_SIZE_OFFSET);
    101   FdtBase = (EFI_PHYSICAL_ADDRESS)(UINTN)Kernel + KernelSize;
    102   Status = gBS->InstallConfigurationTable (&gFdtTableGuid, (VOID *)FdtBase);
    103   ASSERT_EFI_ERROR (Status);
    104 
    105   // Have to cast to UINTN before casting to EFI_PHYSICAL_ADDRESS in order to
    106   // appease GCC.
    107   KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;
    108   KernelDevicePath.Node1.EndingAddress   = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + KernelSize;
    109 
    110   RamdiskDevicePath = NULL;
    111   if (RamdiskSize != 0) {
    112     RamdiskDevicePath = (MEMORY_DEVICE_PATH*)DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*) &MemoryDevicePathTemplate);
    113 
    114     RamdiskDevicePath->Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Ramdisk;
    115     RamdiskDevicePath->Node1.EndingAddress   = ((EFI_PHYSICAL_ADDRESS)(UINTN) Ramdisk) + RamdiskSize;
    116   }
    117 
    118   BdsLoadOptions = (BDS_LOAD_OPTION *)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
    119   ASSERT (BdsLoadOptions != NULL);
    120   BdsLoadOptions->FilePathList = &KernelDevicePath.Node1.Header;
    121   ASSERT (BdsLoadOptions->FilePathList != NULL);
    122   BdsLoadOptions->FilePathListLength = GetDevicePathSize (BdsLoadOptions->FilePathList);
    123   BdsLoadOptions->Attributes = LOAD_OPTION_ACTIVE | LOAD_OPTION_CATEGORY_BOOT;
    124 
    125   AsciiStrToUnicodeStr (KernelArgs, UnicodeArgs);
    126   UnicodeSPrint (InitrdArgs, 64 * sizeof(CHAR16), L" initrd=0x%x,0x%x",
    127 		 (EFI_PHYSICAL_ADDRESS)(UINTN) Ramdisk, RamdiskSize);
    128   StrCat (UnicodeArgs, InitrdArgs);
    129 
    130   VariableSize = 17 * sizeof(CHAR16);
    131   Status = gRT->GetVariable ((CHAR16 *)L"SerialNo", &gHiKeyVariableGuid, NULL,
    132 				&VariableSize, &DataUnicode);
    133   if (!EFI_ERROR (Status)) {
    134     DataUnicode[(VariableSize / sizeof(CHAR16)) - 1] = '\0';
    135     ZeroMem (SerialNoArgs, 40 * sizeof (CHAR16));
    136     UnicodeSPrint (SerialNoArgs, 40 * sizeof(CHAR16), L" androidboot.serialno=%s", DataUnicode);
    137     StrCat (UnicodeArgs, SerialNoArgs);
    138   }
    139 
    140   BdsLoadOptions->OptionalDataSize = StrSize (UnicodeArgs);
    141   BdsLoadOptions->OptionalData = UnicodeArgs;
    142   BdsLoadOptions->Description = NULL;
    143 
    144 
    145   Status = BdsStartEfiApplication (gImageHandle, BdsLoadOptions->FilePathList, BdsLoadOptions->OptionalDataSize, BdsLoadOptions->OptionalData);
    146   if (EFI_ERROR (Status)) {
    147     DEBUG ((EFI_D_ERROR, "Couldn't Boot Linux: %d\n", Status));
    148     return EFI_DEVICE_ERROR;
    149   }
    150 
    151   if (RamdiskDevicePath) {
    152     FreePool (RamdiskDevicePath);
    153   }
    154 
    155   // If we got here we do a confused face because BootLinuxFdt returned,
    156   // reporting success.
    157   DEBUG ((EFI_D_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n"));
    158   return EFI_SUCCESS;
    159 }
    160