3 * Copyright (c) 2011-2015, 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
25 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
26 UINT16 LoadOptionIndexSize
;
28 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
29 Status
= EFI_UNSUPPORTED
;
30 OptionalData
= BootOption
->OptionalData
;
31 LoaderType
= ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
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 ();
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
);
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 ();
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
));
57 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, BootOption
->OptionalDataSize
, BootOption
->OptionalData
);
59 // Clear BootCurrent variable
60 LoadOptionIndexSize
= sizeof(UINT16
);
61 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
62 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
71 IN OUT LIST_ENTRY
*BootOptionList
78 BDS_LOAD_OPTION
* BdsLoadOption
;
79 BDS_LOAD_OPTION_ENTRY
* BdsLoadOptionEntry
;
81 InitializeListHead (BootOptionList
);
83 // Get the Boot Option Order from the environment variable
84 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
85 if (EFI_ERROR(Status
)) {
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
);
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
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
;
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
);
130 BootDescriptionSize
= StrSize (BootDescription
);
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
);
137 // Compute the size of the FilePath list
138 FilePathListLength
= GetUnalignedDevicePathSize (DevicePath
);
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
;
146 // Populate the EFI Load Option and BDS Boot Option structures
150 BootOption
->Attributes
= Attributes
;
151 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
152 EfiLoadOptionPtr
+= sizeof(UINT32
);
154 // FilePath List fields
155 BootOption
->FilePathListLength
= FilePathListLength
;
156 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
157 EfiLoadOptionPtr
+= sizeof(UINT16
);
159 // Boot description fields
160 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
161 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
162 EfiLoadOptionPtr
+= BootDescriptionSize
;
165 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
166 CopyMem (EfiLoadOptionPtr
, DevicePath
, FilePathListLength
);
167 EfiLoadOptionPtr
+= FilePathListLength
;
169 // Optional Data fields, Do unaligned writes
170 BootOption
->OptionalData
= EfiLoadOptionPtr
;
172 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
174 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, ARM_BDS_OPTIONAL_DATA_SIGNATURE
);
175 WriteUnaligned32 ((UINT32
*)(EfiLoadOptionPtr
+ 4), BootType
);
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
;
183 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->CmdLineSize
);
184 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->InitrdSize
), SrcLinuxArguments
->InitrdSize
);
186 if (SrcLinuxArguments
->CmdLineSize
> 0) {
187 CopyMem ((VOID
*)(DestLinuxArguments
+ 1), (VOID
*)(SrcLinuxArguments
+ 1), SrcLinuxArguments
->CmdLineSize
);
190 if (SrcLinuxArguments
->InitrdSize
> 0) {
191 InitrdPathListPtr
= (UINT8
*)((UINTN
)(DestLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
);
192 CopyMem (InitrdPathListPtr
, (VOID
*)((UINTN
)(SrcLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->InitrdSize
);
195 if (OptionalData
!= NULL
) {
196 CopyMem (BootOption
->OptionalData
, OptionalData
, OptionalDataSize
);
199 BootOption
->OptionalDataSize
= OptionalDataSize
;
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 ();
207 // Fill the EFI Load option fields
208 BootOption
->LoadOption
= EfiLoadOption
;
209 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
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
226 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
227 BDS_LOAD_OPTION
* BootOption
;
228 CHAR16 BootVariableName
[9];
233 // Allocate and fill the memory for the BDS Load Option structure
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
));
239 BootOption
= BootOptionEntry
->BdsLoadOption
;
240 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
243 // Set the related environment variables
246 // Create Boot#### environment variable
247 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
248 Status
= gRT
->SetVariable (
250 &gEfiGlobalVariableGuid
,
251 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
252 BootOption
->LoadOptionSize
,
253 BootOption
->LoadOption
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
);
264 // BootOrder does not exist. Create it
265 BootOrderSize
= sizeof(UINT16
);
266 BootOrder
= &(BootOption
->LoadOptionIndex
);
269 // Update (or Create) the BootOrder environment variable
270 Status
= gRT
->SetVariable (
272 &gEfiGlobalVariableGuid
,
273 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
278 // We only free it if the UEFI Variable 'BootOrder' was already existing
279 if (BootOrderSize
> sizeof(UINT16
)) {
280 FreePool (BootOrder
);
283 *BdsLoadOption
= BootOption
;
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
299 CHAR16 BootVariableName
[9];
301 // Update the BDS Load Option structure
302 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
304 // Update the related environment variables
305 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
307 Status
= gRT
->SetVariable (
309 &gEfiGlobalVariableGuid
,
310 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
311 BdsLoadOption
->LoadOptionSize
,
312 BdsLoadOption
->LoadOption
320 IN BDS_LOAD_OPTION
*BootOption
326 UINTN BootOrderCount
;
327 CHAR16 BootVariableName
[9];
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
);
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
) {
342 &BootOrder
[Index
+ 1],
343 (BootOrderCount
- (Index
+ 1)) * sizeof(UINT16
)
350 // Update the BootOrder environment variable
351 Status
= gRT
->SetVariable (
353 &gEfiGlobalVariableGuid
,
354 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
355 BootOrderSize
- sizeof(UINT16
),
360 // Delete Boot#### environment variable
361 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
362 Status
= gRT
->SetVariable (
364 &gEfiGlobalVariableGuid
,
365 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
370 FreePool (BootOrder
);