]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Application/AndroidFastboot/Arm/BootAndroidBootImg.c
EmbeddedPkg: Unload image on EFI_SECURITY_VIOLATION
[mirror_edk2.git] / EmbeddedPkg / Application / AndroidFastboot / Arm / BootAndroidBootImg.c
1 /** @file
2
3 Copyright (c) 2013-2015, ARM Ltd. All rights reserved.<BR>
4
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "AndroidFastbootApp.h"
10
11 #include <Protocol/DevicePath.h>
12 #include <Protocol/LoadedImage.h>
13
14 #include <Library/DevicePathLib.h>
15 #include <Library/UefiBootServicesTableLib.h>
16 #include <Library/UefiLib.h>
17
18 // Device Path representing an image in memory
19 #pragma pack(1)
20 typedef struct {
21 MEMMAP_DEVICE_PATH Node1;
22 EFI_DEVICE_PATH_PROTOCOL End;
23 } MEMORY_DEVICE_PATH;
24 #pragma pack()
25
26 STATIC CONST MEMORY_DEVICE_PATH MemoryDevicePathTemplate =
27 {
28 {
29 {
30 HARDWARE_DEVICE_PATH,
31 HW_MEMMAP_DP,
32 {
33 (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
34 (UINT8)((sizeof (MEMMAP_DEVICE_PATH)) >> 8),
35 },
36 }, // Header
37 0, // StartingAddress (set at runtime)
38 0 // EndingAddress (set at runtime)
39 }, // Node1
40 {
41 END_DEVICE_PATH_TYPE,
42 END_ENTIRE_DEVICE_PATH_SUBTYPE,
43 { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
44 } // End
45 };
46
47
48 /**
49 Start an EFI Application from a Device Path
50
51 @param ParentImageHandle Handle of the calling image
52 @param DevicePath Location of the EFI Application
53
54 @retval EFI_SUCCESS All drivers have been connected
55 @retval EFI_NOT_FOUND The Linux kernel Device Path has not been found
56 @retval EFI_OUT_OF_RESOURCES There is not enough resource memory to store the matching results.
57
58 **/
59 STATIC
60 EFI_STATUS
61 StartEfiApplication (
62 IN EFI_HANDLE ParentImageHandle,
63 IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
64 IN UINTN LoadOptionsSize,
65 IN VOID* LoadOptions
66 )
67 {
68 EFI_STATUS Status;
69 EFI_HANDLE ImageHandle;
70 EFI_LOADED_IMAGE_PROTOCOL* LoadedImage;
71
72 // Load the image from the device path with Boot Services function
73 Status = gBS->LoadImage (TRUE, ParentImageHandle, DevicePath, NULL, 0,
74 &ImageHandle);
75 if (EFI_ERROR (Status)) {
76 //
77 // With EFI_SECURITY_VIOLATION retval, the Image was loaded and an ImageHandle was created
78 // with a valid EFI_LOADED_IMAGE_PROTOCOL, but the image can not be started right now.
79 // If the caller doesn't have the option to defer the execution of an image, we should
80 // unload image for the EFI_SECURITY_VIOLATION to avoid resource leak.
81 //
82 if (Status == EFI_SECURITY_VIOLATION) {
83 gBS->UnloadImage (ImageHandle);
84 }
85 return Status;
86 }
87
88 // Passed LoadOptions to the EFI Application
89 if (LoadOptionsSize != 0) {
90 Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid,
91 (VOID **) &LoadedImage);
92 if (EFI_ERROR (Status)) {
93 return Status;
94 }
95
96 LoadedImage->LoadOptionsSize = LoadOptionsSize;
97 LoadedImage->LoadOptions = LoadOptions;
98 }
99
100 // Before calling the image, enable the Watchdog Timer for the 5 Minute period
101 gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
102 // Start the image
103 Status = gBS->StartImage (ImageHandle, NULL, NULL);
104 // Clear the Watchdog Timer after the image returns
105 gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
106
107 return Status;
108 }
109
110 EFI_STATUS
111 BootAndroidBootImg (
112 IN UINTN BufferSize,
113 IN VOID *Buffer
114 )
115 {
116 EFI_STATUS Status;
117 CHAR8 KernelArgs[ANDROID_BOOTIMG_KERNEL_ARGS_SIZE];
118 VOID *Kernel;
119 UINTN KernelSize;
120 VOID *Ramdisk;
121 UINTN RamdiskSize;
122 MEMORY_DEVICE_PATH KernelDevicePath;
123 CHAR16 *LoadOptions, *NewLoadOptions;
124
125 Status = ParseAndroidBootImg (
126 Buffer,
127 &Kernel,
128 &KernelSize,
129 &Ramdisk,
130 &RamdiskSize,
131 KernelArgs
132 );
133 if (EFI_ERROR (Status)) {
134 return Status;
135 }
136
137 KernelDevicePath = MemoryDevicePathTemplate;
138
139 // Have to cast to UINTN before casting to EFI_PHYSICAL_ADDRESS in order to
140 // appease GCC.
141 KernelDevicePath.Node1.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel;
142 KernelDevicePath.Node1.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Kernel + KernelSize;
143
144 // Initialize Linux command line
145 LoadOptions = CatSPrint (NULL, L"%a", KernelArgs);
146 if (LoadOptions == NULL) {
147 return EFI_OUT_OF_RESOURCES;
148 }
149
150 if (RamdiskSize != 0) {
151 NewLoadOptions = CatSPrint (LoadOptions, L" initrd=0x%x,0x%x",
152 (UINTN)Ramdisk, RamdiskSize);
153 FreePool (LoadOptions);
154 if (NewLoadOptions == NULL) {
155 return EFI_OUT_OF_RESOURCES;
156 }
157 LoadOptions = NewLoadOptions;
158 }
159
160 Status = StartEfiApplication (gImageHandle,
161 (EFI_DEVICE_PATH_PROTOCOL *) &KernelDevicePath,
162 StrSize (LoadOptions),
163 LoadOptions);
164 if (EFI_ERROR (Status)) {
165 DEBUG ((EFI_D_ERROR, "Couldn't Boot Linux: %d\n", Status));
166 Status = EFI_DEVICE_ERROR;
167 goto FreeLoadOptions;
168 }
169
170 // If we got here we do a confused face because BootLinuxFdt returned,
171 // reporting success.
172 DEBUG ((EFI_D_ERROR, "WARNING: BdsBootLinuxFdt returned EFI_SUCCESS.\n"));
173 return EFI_SUCCESS;
174
175 FreeLoadOptions:
176 FreePool (LoadOptions);
177 return Status;
178 }