3 * Copyright (c) 2011-2014, ARM Limited. All rights reserved.
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
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.
15 #include <Guid/ArmGlobalVariableHob.h>
16 #include "BdsInternal.h"
20 IN BDS_LOAD_OPTION
*BootOption
24 EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL
* EfiDevicePathFromTextProtocol
;
26 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
27 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
28 EFI_DEVICE_PATH_PROTOCOL
* FdtDevicePath
;
29 EFI_DEVICE_PATH_PROTOCOL
* DefaultFdtDevicePath
;
30 UINTN FdtDevicePathSize
;
33 EFI_DEVICE_PATH
* Initrd
;
34 UINT16 LoadOptionIndexSize
;
36 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
37 Status
= EFI_UNSUPPORTED
;
38 OptionalData
= BootOption
->OptionalData
;
39 LoaderType
= ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
41 if (LoaderType
== BDS_LOADER_EFI_APPLICATION
) {
42 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_APP
) {
43 // Need to connect every drivers to ensure no dependencies are missing for the application
44 BdsConnectAllDrivers ();
47 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, 0, NULL
);
48 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
49 LinuxArguments
= &(OptionalData
->Arguments
.LinuxArguments
);
50 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
51 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
54 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
59 Status
= BdsBootLinuxAtag (BootOption
->FilePathList
,
61 (CHAR8
*)(LinuxArguments
+ 1)); // CmdLine
62 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) {
63 LinuxArguments
= &(OptionalData
->Arguments
.LinuxArguments
);
64 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
65 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
68 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
73 // Get the default FDT device path
74 Status
= gBS
->LocateProtocol (&gEfiDevicePathFromTextProtocolGuid
, NULL
, (VOID
**)&EfiDevicePathFromTextProtocol
);
75 ASSERT_EFI_ERROR(Status
);
76 DefaultFdtDevicePath
= EfiDevicePathFromTextProtocol
->ConvertTextToDevicePath ((CHAR16
*)PcdGetPtr(PcdFdtDevicePath
));
78 // Get the FDT device path
79 FdtDevicePathSize
= GetDevicePathSize (DefaultFdtDevicePath
);
80 Status
= GetEnvironmentVariable ((CHAR16
*)L
"Fdt", &gArmGlobalVariableGuid
,
81 DefaultFdtDevicePath
, &FdtDevicePathSize
, (VOID
**)&FdtDevicePath
);
82 ASSERT_EFI_ERROR(Status
);
84 Status
= BdsBootLinuxFdt (BootOption
->FilePathList
,
86 (CHAR8
*)(LinuxArguments
+ 1),
89 FreePool (DefaultFdtDevicePath
);
90 FreePool (FdtDevicePath
);
93 // Connect all the drivers if the EFI Application is not a EFI OS Loader
94 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_APP
) {
95 BdsConnectAllDrivers ();
98 // Set BootCurrent variable
99 LoadOptionIndexSize
= sizeof(UINT16
);
100 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
101 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
102 LoadOptionIndexSize
, &(BootOption
->LoadOptionIndex
));
104 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, BootOption
->OptionalDataSize
, BootOption
->OptionalData
);
106 // Clear BootCurrent variable
107 LoadOptionIndexSize
= sizeof(UINT16
);
108 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
109 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
118 IN OUT LIST_ENTRY
*BootOptionList
125 BDS_LOAD_OPTION
* BdsLoadOption
;
126 BDS_LOAD_OPTION_ENTRY
* BdsLoadOptionEntry
;
128 InitializeListHead (BootOptionList
);
130 // Get the Boot Option Order from the environment variable
131 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
132 if (EFI_ERROR(Status
)) {
136 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
137 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
138 if (!EFI_ERROR(Status
)) {
139 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY
));
140 BdsLoadOptionEntry
->BdsLoadOption
= BdsLoadOption
;
141 InsertTailList (BootOptionList
,&BdsLoadOptionEntry
->Link
);
145 FreePool (BootOrder
);
152 BootOptionSetFields (
153 IN BDS_LOAD_OPTION
* BootOption
,
154 IN UINT32 Attributes
,
155 IN CHAR16
* BootDescription
,
156 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
157 IN ARM_BDS_LOADER_TYPE BootType
,
158 IN UINT8
* OptionalData
,
159 IN UINTN OptionalDataSize
162 EFI_LOAD_OPTION EfiLoadOption
;
163 UINTN EfiLoadOptionSize
;
164 UINTN BootDescriptionSize
;
165 UINT16 FilePathListLength
;
166 UINT8
* EfiLoadOptionPtr
;
167 UINT8
* InitrdPathListPtr
;
168 ARM_BDS_LINUX_ARGUMENTS
* DestLinuxArguments
;
169 ARM_BDS_LINUX_ARGUMENTS
* SrcLinuxArguments
;
170 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
172 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
173 if (BootOption
->LoadOption
) {
174 FreePool (BootOption
->LoadOption
);
177 BootDescriptionSize
= StrSize (BootDescription
);
179 // Fixup the size in case of entry specific to ArmPlatformPkg/Bds
180 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
181 OptionalDataSize
+= sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER
);
184 // Compute the size of the FilePath list
185 FilePathListLength
= GetUnalignedDevicePathSize (DevicePath
);
187 // Allocate the memory for the EFI Load Option
188 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ OptionalDataSize
;
189 EfiLoadOption
= (EFI_LOAD_OPTION
)AllocatePool(EfiLoadOptionSize
);
190 EfiLoadOptionPtr
= EfiLoadOption
;
193 // Populate the EFI Load Option and BDS Boot Option structures
197 BootOption
->Attributes
= Attributes
;
198 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
199 EfiLoadOptionPtr
+= sizeof(UINT32
);
201 // FilePath List fields
202 BootOption
->FilePathListLength
= FilePathListLength
;
203 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
204 EfiLoadOptionPtr
+= sizeof(UINT16
);
206 // Boot description fields
207 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
208 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
209 EfiLoadOptionPtr
+= BootDescriptionSize
;
212 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
213 CopyMem (EfiLoadOptionPtr
, DevicePath
, FilePathListLength
);
214 EfiLoadOptionPtr
+= FilePathListLength
;
216 // Optional Data fields, Do unaligned writes
217 BootOption
->OptionalData
= EfiLoadOptionPtr
;
219 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
221 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, ARM_BDS_OPTIONAL_DATA_SIGNATURE
);
222 WriteUnaligned32 ((UINT32
*)(EfiLoadOptionPtr
+ 4), BootType
);
224 // OptionalData should have been initialized by the caller of this function
225 ASSERT (OptionalData
!= NULL
);
226 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)OptionalData
;
227 SrcLinuxArguments
= &(BootArguments
->LinuxArguments
);
228 DestLinuxArguments
= &((ARM_BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
.LinuxArguments
;
230 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->CmdLineSize
);
231 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->InitrdSize
), SrcLinuxArguments
->InitrdSize
);
233 if (SrcLinuxArguments
->CmdLineSize
> 0) {
234 CopyMem ((VOID
*)(DestLinuxArguments
+ 1), (VOID
*)(SrcLinuxArguments
+ 1), SrcLinuxArguments
->CmdLineSize
);
237 if (SrcLinuxArguments
->InitrdSize
> 0) {
238 InitrdPathListPtr
= (UINT8
*)((UINTN
)(DestLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
);
239 CopyMem (InitrdPathListPtr
, (VOID
*)((UINTN
)(SrcLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->InitrdSize
);
242 if (OptionalData
!= NULL
) {
243 CopyMem (BootOption
->OptionalData
, OptionalData
, OptionalDataSize
);
246 BootOption
->OptionalDataSize
= OptionalDataSize
;
248 // If this function is called at the creation of the Boot Device entry (not at the update) the
249 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
250 if (BootOption
->LoadOptionSize
== 0) {
251 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
254 // Fill the EFI Load option fields
255 BootOption
->LoadOption
= EfiLoadOption
;
256 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
263 IN UINT32 Attributes
,
264 IN CHAR16
* BootDescription
,
265 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
266 IN ARM_BDS_LOADER_TYPE BootType
,
267 IN UINT8
* OptionalData
,
268 IN UINTN OptionalDataSize
,
269 OUT BDS_LOAD_OPTION
** BdsLoadOption
273 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
274 BDS_LOAD_OPTION
* BootOption
;
275 CHAR16 BootVariableName
[9];
280 // Allocate and fill the memory for the BDS Load Option structure
282 BootOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY
));
283 InitializeListHead (&BootOptionEntry
->Link
);
284 BootOptionEntry
->BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
286 BootOption
= BootOptionEntry
->BdsLoadOption
;
287 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
290 // Set the related environment variables
293 // Create Boot#### environment variable
294 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
295 Status
= gRT
->SetVariable (
297 &gEfiGlobalVariableGuid
,
298 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
299 BootOption
->LoadOptionSize
,
300 BootOption
->LoadOption
303 // Add the new Boot Index to the list
304 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
305 if (!EFI_ERROR(Status
)) {
306 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
307 // Add the new index at the end
308 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
309 BootOrderSize
+= sizeof(UINT16
);
311 // BootOrder does not exist. Create it
312 BootOrderSize
= sizeof(UINT16
);
313 BootOrder
= &(BootOption
->LoadOptionIndex
);
316 // Update (or Create) the BootOrder environment variable
317 Status
= gRT
->SetVariable (
319 &gEfiGlobalVariableGuid
,
320 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
325 // We only free it if the UEFI Variable 'BootOrder' was already existing
326 if (BootOrderSize
> sizeof(UINT16
)) {
327 FreePool (BootOrder
);
330 *BdsLoadOption
= BootOption
;
336 IN BDS_LOAD_OPTION
* BdsLoadOption
,
337 IN UINT32 Attributes
,
338 IN CHAR16
* BootDescription
,
339 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
340 IN ARM_BDS_LOADER_TYPE BootType
,
341 IN UINT8
* OptionalData
,
342 IN UINTN OptionalDataSize
346 CHAR16 BootVariableName
[9];
348 // Update the BDS Load Option structure
349 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
351 // Update the related environment variables
352 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
354 Status
= gRT
->SetVariable (
356 &gEfiGlobalVariableGuid
,
357 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
358 BdsLoadOption
->LoadOptionSize
,
359 BdsLoadOption
->LoadOption
367 IN BDS_LOAD_OPTION
*BootOption
373 UINTN BootOrderCount
;
374 CHAR16 BootVariableName
[9];
377 // Remove the entry from the BootOrder environment variable
378 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
379 if (!EFI_ERROR(Status
)) {
380 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
382 // Find the index of the removed entry
383 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
384 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
385 // If it the last entry we do not need to rearrange the BootOrder list
386 if (Index
+ 1 != BootOrderCount
) {
389 &BootOrder
[Index
+ 1],
390 (BootOrderCount
- (Index
+ 1)) * sizeof(UINT16
)
397 // Update the BootOrder environment variable
398 Status
= gRT
->SetVariable (
400 &gEfiGlobalVariableGuid
,
401 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
402 BootOrderSize
- sizeof(UINT16
),
407 // Delete Boot#### environment variable
408 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
409 Status
= gRT
->SetVariable (
411 &gEfiGlobalVariableGuid
,
412 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
417 FreePool (BootOrder
);