]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootOption.c
ArmPkg/BdsLib: Remove Linux loader from BdsLib
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootOption.c
1 /** @file
2 *
3 * Copyright (c) 2011-2015, ARM Limited. All rights reserved.
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 <Guid/ArmGlobalVariableHob.h>
16 #include "BdsInternal.h"
17
18 EFI_STATUS
19 BootOptionStart (
20 IN BDS_LOAD_OPTION *BootOption
21 )
22 {
23 EFI_STATUS Status;
24 UINT32 LoaderType;
25 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
26 UINT16 LoadOptionIndexSize;
27
28 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
29 Status = EFI_UNSUPPORTED;
30 OptionalData = BootOption->OptionalData;
31 LoaderType = ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
32
33 if (LoaderType == BDS_LOADER_EFI_APPLICATION) {
34 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {
35 // Need to connect every drivers to ensure no dependencies are missing for the application
36 BdsConnectAllDrivers ();
37 }
38
39 Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, 0, NULL);
40 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) {
41 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
42 } else if (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT) {
43 ASSERT_EFI_ERROR (EFI_UNSUPPORTED);
44 }
45 } else {
46 // Connect all the drivers if the EFI Application is not a EFI OS Loader
47 if ((BootOption->Attributes & LOAD_OPTION_CATEGORY) == LOAD_OPTION_CATEGORY_APP) {
48 BdsConnectAllDrivers ();
49 }
50
51 // Set BootCurrent variable
52 LoadOptionIndexSize = sizeof(UINT16);
53 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
54 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
55 LoadOptionIndexSize, &(BootOption->LoadOptionIndex));
56
57 Status = BdsStartEfiApplication (gImageHandle, BootOption->FilePathList, BootOption->OptionalDataSize, BootOption->OptionalData);
58
59 // Clear BootCurrent variable
60 LoadOptionIndexSize = sizeof(UINT16);
61 gRT->SetVariable (L"BootCurrent", &gEfiGlobalVariableGuid,
62 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
63 0, NULL);
64 }
65
66 return Status;
67 }
68
69 EFI_STATUS
70 BootOptionList (
71 IN OUT LIST_ENTRY *BootOptionList
72 )
73 {
74 EFI_STATUS Status;
75 UINTN Index;
76 UINT16* BootOrder;
77 UINTN BootOrderSize;
78 BDS_LOAD_OPTION* BdsLoadOption;
79 BDS_LOAD_OPTION_ENTRY* BdsLoadOptionEntry;
80
81 InitializeListHead (BootOptionList);
82
83 // Get the Boot Option Order from the environment variable
84 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
85 if (EFI_ERROR(Status)) {
86 return Status;
87 }
88
89 for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
90 Status = BootOptionFromLoadOptionIndex (BootOrder[Index], &BdsLoadOption);
91 if (!EFI_ERROR(Status)) {
92 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY));
93 BdsLoadOptionEntry->BdsLoadOption = BdsLoadOption;
94 InsertTailList (BootOptionList,&BdsLoadOptionEntry->Link);
95 }
96 }
97
98 FreePool (BootOrder);
99
100 return EFI_SUCCESS;
101 }
102
103 STATIC
104 EFI_STATUS
105 BootOptionSetFields (
106 IN BDS_LOAD_OPTION* BootOption,
107 IN UINT32 Attributes,
108 IN CHAR16* BootDescription,
109 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
110 IN ARM_BDS_LOADER_TYPE BootType,
111 IN UINT8* OptionalData,
112 IN UINTN OptionalDataSize
113 )
114 {
115 EFI_LOAD_OPTION *EfiLoadOption;
116 UINTN EfiLoadOptionSize;
117 UINTN BootDescriptionSize;
118 UINT16 FilePathListLength;
119 UINT8* EfiLoadOptionPtr;
120 UINT8* InitrdPathListPtr;
121 ARM_BDS_LINUX_ARGUMENTS* DestLinuxArguments;
122 ARM_BDS_LINUX_ARGUMENTS* SrcLinuxArguments;
123 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
124
125 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
126 if (BootOption->LoadOption) {
127 FreePool (BootOption->LoadOption);
128 }
129
130 BootDescriptionSize = StrSize (BootDescription);
131
132 // Fixup the size in case of entry specific to ArmPlatformPkg/Bds
133 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
134 OptionalDataSize += sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER);
135 }
136
137 // Compute the size of the FilePath list
138 FilePathListLength = GetUnalignedDevicePathSize (DevicePath);
139
140 // Allocate the memory for the EFI Load Option
141 EfiLoadOptionSize = sizeof(UINT32) + sizeof(UINT16) + BootDescriptionSize + FilePathListLength + OptionalDataSize;
142 EfiLoadOption = (EFI_LOAD_OPTION *)AllocatePool(EfiLoadOptionSize);
143 EfiLoadOptionPtr = (UINT8 *)EfiLoadOption;
144
145 //
146 // Populate the EFI Load Option and BDS Boot Option structures
147 //
148
149 // Attributes fields
150 BootOption->Attributes = Attributes;
151 *(UINT32*)EfiLoadOptionPtr = Attributes;
152 EfiLoadOptionPtr += sizeof(UINT32);
153
154 // FilePath List fields
155 BootOption->FilePathListLength = FilePathListLength;
156 *(UINT16*)EfiLoadOptionPtr = FilePathListLength;
157 EfiLoadOptionPtr += sizeof(UINT16);
158
159 // Boot description fields
160 BootOption->Description = (CHAR16*)EfiLoadOptionPtr;
161 CopyMem (EfiLoadOptionPtr, BootDescription, BootDescriptionSize);
162 EfiLoadOptionPtr += BootDescriptionSize;
163
164 // File path fields
165 BootOption->FilePathList = (EFI_DEVICE_PATH_PROTOCOL*)EfiLoadOptionPtr;
166 CopyMem (EfiLoadOptionPtr, DevicePath, FilePathListLength);
167 EfiLoadOptionPtr += FilePathListLength;
168
169 // Optional Data fields, Do unaligned writes
170 BootOption->OptionalData = EfiLoadOptionPtr;
171
172 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
173 // Write the header
174 WriteUnaligned32 ((UINT32 *)EfiLoadOptionPtr, ARM_BDS_OPTIONAL_DATA_SIGNATURE);
175 WriteUnaligned32 ((UINT32 *)(EfiLoadOptionPtr + 4), BootType);
176
177 // OptionalData should have been initialized by the caller of this function
178 ASSERT (OptionalData != NULL);
179 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)OptionalData;
180 SrcLinuxArguments = &(BootArguments->LinuxArguments);
181 DestLinuxArguments = &((ARM_BDS_LOADER_OPTIONAL_DATA*)EfiLoadOptionPtr)->Arguments.LinuxArguments;
182
183 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->CmdLineSize), SrcLinuxArguments->CmdLineSize);
184 WriteUnaligned16 ((UINT16 *)&(DestLinuxArguments->InitrdSize), SrcLinuxArguments->InitrdSize);
185
186 if (SrcLinuxArguments->CmdLineSize > 0) {
187 CopyMem ((VOID*)(DestLinuxArguments + 1), (VOID*)(SrcLinuxArguments + 1), SrcLinuxArguments->CmdLineSize);
188 }
189
190 if (SrcLinuxArguments->InitrdSize > 0) {
191 InitrdPathListPtr = (UINT8*)((UINTN)(DestLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize);
192 CopyMem (InitrdPathListPtr, (VOID*)((UINTN)(SrcLinuxArguments + 1) + SrcLinuxArguments->CmdLineSize), SrcLinuxArguments->InitrdSize);
193 }
194 } else {
195 if (OptionalData != NULL) {
196 CopyMem (BootOption->OptionalData, OptionalData, OptionalDataSize);
197 }
198 }
199 BootOption->OptionalDataSize = OptionalDataSize;
200
201 // If this function is called at the creation of the Boot Device entry (not at the update) the
202 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
203 if (BootOption->LoadOptionSize == 0) {
204 BootOption->LoadOptionIndex = BootOptionAllocateBootIndex ();
205 }
206
207 // Fill the EFI Load option fields
208 BootOption->LoadOption = EfiLoadOption;
209 BootOption->LoadOptionSize = EfiLoadOptionSize;
210
211 return EFI_SUCCESS;
212 }
213
214 EFI_STATUS
215 BootOptionCreate (
216 IN UINT32 Attributes,
217 IN CHAR16* BootDescription,
218 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
219 IN ARM_BDS_LOADER_TYPE BootType,
220 IN UINT8* OptionalData,
221 IN UINTN OptionalDataSize,
222 OUT BDS_LOAD_OPTION** BdsLoadOption
223 )
224 {
225 EFI_STATUS Status;
226 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
227 BDS_LOAD_OPTION* BootOption;
228 CHAR16 BootVariableName[9];
229 UINT16* BootOrder;
230 UINTN BootOrderSize;
231
232 //
233 // Allocate and fill the memory for the BDS Load Option structure
234 //
235 BootOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY));
236 InitializeListHead (&BootOptionEntry->Link);
237 BootOptionEntry->BdsLoadOption = (BDS_LOAD_OPTION*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION));
238
239 BootOption = BootOptionEntry->BdsLoadOption;
240 BootOptionSetFields (BootOption, Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);
241
242 //
243 // Set the related environment variables
244 //
245
246 // Create Boot#### environment variable
247 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
248 Status = gRT->SetVariable (
249 BootVariableName,
250 &gEfiGlobalVariableGuid,
251 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
252 BootOption->LoadOptionSize,
253 BootOption->LoadOption
254 );
255
256 // Add the new Boot Index to the list
257 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
258 if (!EFI_ERROR(Status)) {
259 BootOrder = ReallocatePool (BootOrderSize, BootOrderSize + sizeof(UINT16), BootOrder);
260 // Add the new index at the end
261 BootOrder[BootOrderSize / sizeof(UINT16)] = BootOption->LoadOptionIndex;
262 BootOrderSize += sizeof(UINT16);
263 } else {
264 // BootOrder does not exist. Create it
265 BootOrderSize = sizeof(UINT16);
266 BootOrder = &(BootOption->LoadOptionIndex);
267 }
268
269 // Update (or Create) the BootOrder environment variable
270 Status = gRT->SetVariable (
271 L"BootOrder",
272 &gEfiGlobalVariableGuid,
273 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
274 BootOrderSize,
275 BootOrder
276 );
277
278 // We only free it if the UEFI Variable 'BootOrder' was already existing
279 if (BootOrderSize > sizeof(UINT16)) {
280 FreePool (BootOrder);
281 }
282
283 *BdsLoadOption = BootOption;
284 return Status;
285 }
286
287 EFI_STATUS
288 BootOptionUpdate (
289 IN BDS_LOAD_OPTION* BdsLoadOption,
290 IN UINT32 Attributes,
291 IN CHAR16* BootDescription,
292 IN EFI_DEVICE_PATH_PROTOCOL* DevicePath,
293 IN ARM_BDS_LOADER_TYPE BootType,
294 IN UINT8* OptionalData,
295 IN UINTN OptionalDataSize
296 )
297 {
298 EFI_STATUS Status;
299 CHAR16 BootVariableName[9];
300
301 // Update the BDS Load Option structure
302 BootOptionSetFields (BdsLoadOption, Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);
303
304 // Update the related environment variables
305 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BdsLoadOption->LoadOptionIndex);
306
307 Status = gRT->SetVariable (
308 BootVariableName,
309 &gEfiGlobalVariableGuid,
310 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
311 BdsLoadOption->LoadOptionSize,
312 BdsLoadOption->LoadOption
313 );
314
315 return Status;
316 }
317
318 EFI_STATUS
319 BootOptionDelete (
320 IN BDS_LOAD_OPTION *BootOption
321 )
322 {
323 UINTN Index;
324 UINTN BootOrderSize;
325 UINT16* BootOrder;
326 UINTN BootOrderCount;
327 CHAR16 BootVariableName[9];
328 EFI_STATUS Status;
329
330 // Remove the entry from the BootOrder environment variable
331 Status = GetGlobalEnvironmentVariable (L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder);
332 if (!EFI_ERROR(Status)) {
333 BootOrderCount = BootOrderSize / sizeof(UINT16);
334
335 // Find the index of the removed entry
336 for (Index = 0; Index < BootOrderCount; Index++) {
337 if (BootOrder[Index] == BootOption->LoadOptionIndex) {
338 // If it the last entry we do not need to rearrange the BootOrder list
339 if (Index + 1 != BootOrderCount) {
340 CopyMem (
341 &BootOrder[Index],
342 &BootOrder[Index + 1],
343 (BootOrderCount - (Index + 1)) * sizeof(UINT16)
344 );
345 }
346 break;
347 }
348 }
349
350 // Update the BootOrder environment variable
351 Status = gRT->SetVariable (
352 L"BootOrder",
353 &gEfiGlobalVariableGuid,
354 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
355 BootOrderSize - sizeof(UINT16),
356 BootOrder
357 );
358 }
359
360 // Delete Boot#### environment variable
361 UnicodeSPrint (BootVariableName, 9 * sizeof(CHAR16), L"Boot%04X", BootOption->LoadOptionIndex);
362 Status = gRT->SetVariable (
363 BootVariableName,
364 &gEfiGlobalVariableGuid,
365 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
366 0,
367 NULL
368 );
369
370 FreePool (BootOrder);
371
372 return Status;
373 }