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
BootAndroidBootImg(IN UINTN BufferSize,IN VOID * Buffer)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 = 512;
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