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
25 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
26 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
29 EFI_DEVICE_PATH
* Initrd
;
30 UINT16 LoadOptionIndexSize
;
32 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
33 Status
= EFI_UNSUPPORTED
;
34 OptionalData
= BootOption
->OptionalData
;
35 LoaderType
= ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
37 if (LoaderType
== BDS_LOADER_EFI_APPLICATION
) {
38 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_APP
) {
39 // Need to connect every drivers to ensure no dependencies are missing for the application
40 BdsConnectAllDrivers ();
43 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, 0, NULL
);
44 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
45 LinuxArguments
= &(OptionalData
->Arguments
.LinuxArguments
);
46 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
47 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
50 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
55 Status
= BdsBootLinuxAtag (BootOption
->FilePathList
,
57 (CHAR8
*)(LinuxArguments
+ 1)); // CmdLine
58 } else if (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
) {
59 LinuxArguments
= &(OptionalData
->Arguments
.LinuxArguments
);
60 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
61 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
64 Initrd
= GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
));
68 Status
= BdsBootLinuxFdt (
69 BootOption
->FilePathList
,
71 (CHAR8
*)(LinuxArguments
+ 1)
75 // Connect all the drivers if the EFI Application is not a EFI OS Loader
76 if ((BootOption
->Attributes
& LOAD_OPTION_CATEGORY
) == LOAD_OPTION_CATEGORY_APP
) {
77 BdsConnectAllDrivers ();
80 // Set BootCurrent variable
81 LoadOptionIndexSize
= sizeof(UINT16
);
82 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
83 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
84 LoadOptionIndexSize
, &(BootOption
->LoadOptionIndex
));
86 Status
= BdsStartEfiApplication (gImageHandle
, BootOption
->FilePathList
, BootOption
->OptionalDataSize
, BootOption
->OptionalData
);
88 // Clear BootCurrent variable
89 LoadOptionIndexSize
= sizeof(UINT16
);
90 gRT
->SetVariable (L
"BootCurrent", &gEfiGlobalVariableGuid
,
91 EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
100 IN OUT LIST_ENTRY
*BootOptionList
107 BDS_LOAD_OPTION
* BdsLoadOption
;
108 BDS_LOAD_OPTION_ENTRY
* BdsLoadOptionEntry
;
110 InitializeListHead (BootOptionList
);
112 // Get the Boot Option Order from the environment variable
113 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
114 if (EFI_ERROR(Status
)) {
118 for (Index
= 0; Index
< BootOrderSize
/ sizeof (UINT16
); Index
++) {
119 Status
= BootOptionFromLoadOptionIndex (BootOrder
[Index
], &BdsLoadOption
);
120 if (!EFI_ERROR(Status
)) {
121 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool(sizeof(BDS_LOAD_OPTION_ENTRY
));
122 BdsLoadOptionEntry
->BdsLoadOption
= BdsLoadOption
;
123 InsertTailList (BootOptionList
,&BdsLoadOptionEntry
->Link
);
127 FreePool (BootOrder
);
134 BootOptionSetFields (
135 IN BDS_LOAD_OPTION
* BootOption
,
136 IN UINT32 Attributes
,
137 IN CHAR16
* BootDescription
,
138 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
139 IN ARM_BDS_LOADER_TYPE BootType
,
140 IN UINT8
* OptionalData
,
141 IN UINTN OptionalDataSize
144 EFI_LOAD_OPTION
*EfiLoadOption
;
145 UINTN EfiLoadOptionSize
;
146 UINTN BootDescriptionSize
;
147 UINT16 FilePathListLength
;
148 UINT8
* EfiLoadOptionPtr
;
149 UINT8
* InitrdPathListPtr
;
150 ARM_BDS_LINUX_ARGUMENTS
* DestLinuxArguments
;
151 ARM_BDS_LINUX_ARGUMENTS
* SrcLinuxArguments
;
152 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
154 // If we are overwriting an existent Boot Option then we have to free previously allocated memory
155 if (BootOption
->LoadOption
) {
156 FreePool (BootOption
->LoadOption
);
159 BootDescriptionSize
= StrSize (BootDescription
);
161 // Fixup the size in case of entry specific to ArmPlatformPkg/Bds
162 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
163 OptionalDataSize
+= sizeof(ARM_BDS_LOADER_OPTIONAL_DATA_HEADER
);
166 // Compute the size of the FilePath list
167 FilePathListLength
= GetUnalignedDevicePathSize (DevicePath
);
169 // Allocate the memory for the EFI Load Option
170 EfiLoadOptionSize
= sizeof(UINT32
) + sizeof(UINT16
) + BootDescriptionSize
+ FilePathListLength
+ OptionalDataSize
;
171 EfiLoadOption
= (EFI_LOAD_OPTION
*)AllocatePool(EfiLoadOptionSize
);
172 EfiLoadOptionPtr
= (UINT8
*)EfiLoadOption
;
175 // Populate the EFI Load Option and BDS Boot Option structures
179 BootOption
->Attributes
= Attributes
;
180 *(UINT32
*)EfiLoadOptionPtr
= Attributes
;
181 EfiLoadOptionPtr
+= sizeof(UINT32
);
183 // FilePath List fields
184 BootOption
->FilePathListLength
= FilePathListLength
;
185 *(UINT16
*)EfiLoadOptionPtr
= FilePathListLength
;
186 EfiLoadOptionPtr
+= sizeof(UINT16
);
188 // Boot description fields
189 BootOption
->Description
= (CHAR16
*)EfiLoadOptionPtr
;
190 CopyMem (EfiLoadOptionPtr
, BootDescription
, BootDescriptionSize
);
191 EfiLoadOptionPtr
+= BootDescriptionSize
;
194 BootOption
->FilePathList
= (EFI_DEVICE_PATH_PROTOCOL
*)EfiLoadOptionPtr
;
195 CopyMem (EfiLoadOptionPtr
, DevicePath
, FilePathListLength
);
196 EfiLoadOptionPtr
+= FilePathListLength
;
198 // Optional Data fields, Do unaligned writes
199 BootOption
->OptionalData
= EfiLoadOptionPtr
;
201 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
203 WriteUnaligned32 ((UINT32
*)EfiLoadOptionPtr
, ARM_BDS_OPTIONAL_DATA_SIGNATURE
);
204 WriteUnaligned32 ((UINT32
*)(EfiLoadOptionPtr
+ 4), BootType
);
206 // OptionalData should have been initialized by the caller of this function
207 ASSERT (OptionalData
!= NULL
);
208 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)OptionalData
;
209 SrcLinuxArguments
= &(BootArguments
->LinuxArguments
);
210 DestLinuxArguments
= &((ARM_BDS_LOADER_OPTIONAL_DATA
*)EfiLoadOptionPtr
)->Arguments
.LinuxArguments
;
212 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->CmdLineSize
);
213 WriteUnaligned16 ((UINT16
*)&(DestLinuxArguments
->InitrdSize
), SrcLinuxArguments
->InitrdSize
);
215 if (SrcLinuxArguments
->CmdLineSize
> 0) {
216 CopyMem ((VOID
*)(DestLinuxArguments
+ 1), (VOID
*)(SrcLinuxArguments
+ 1), SrcLinuxArguments
->CmdLineSize
);
219 if (SrcLinuxArguments
->InitrdSize
> 0) {
220 InitrdPathListPtr
= (UINT8
*)((UINTN
)(DestLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
);
221 CopyMem (InitrdPathListPtr
, (VOID
*)((UINTN
)(SrcLinuxArguments
+ 1) + SrcLinuxArguments
->CmdLineSize
), SrcLinuxArguments
->InitrdSize
);
224 if (OptionalData
!= NULL
) {
225 CopyMem (BootOption
->OptionalData
, OptionalData
, OptionalDataSize
);
228 BootOption
->OptionalDataSize
= OptionalDataSize
;
230 // If this function is called at the creation of the Boot Device entry (not at the update) the
231 // BootOption->LoadOptionSize must be zero then we get a new BootIndex for this entry
232 if (BootOption
->LoadOptionSize
== 0) {
233 BootOption
->LoadOptionIndex
= BootOptionAllocateBootIndex ();
236 // Fill the EFI Load option fields
237 BootOption
->LoadOption
= EfiLoadOption
;
238 BootOption
->LoadOptionSize
= EfiLoadOptionSize
;
245 IN UINT32 Attributes
,
246 IN CHAR16
* BootDescription
,
247 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
248 IN ARM_BDS_LOADER_TYPE BootType
,
249 IN UINT8
* OptionalData
,
250 IN UINTN OptionalDataSize
,
251 OUT BDS_LOAD_OPTION
** BdsLoadOption
255 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
256 BDS_LOAD_OPTION
* BootOption
;
257 CHAR16 BootVariableName
[9];
262 // Allocate and fill the memory for the BDS Load Option structure
264 BootOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof (BDS_LOAD_OPTION_ENTRY
));
265 InitializeListHead (&BootOptionEntry
->Link
);
266 BootOptionEntry
->BdsLoadOption
= (BDS_LOAD_OPTION
*)AllocateZeroPool (sizeof(BDS_LOAD_OPTION
));
268 BootOption
= BootOptionEntry
->BdsLoadOption
;
269 BootOptionSetFields (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
272 // Set the related environment variables
275 // Create Boot#### environment variable
276 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
277 Status
= gRT
->SetVariable (
279 &gEfiGlobalVariableGuid
,
280 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
281 BootOption
->LoadOptionSize
,
282 BootOption
->LoadOption
285 // Add the new Boot Index to the list
286 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
287 if (!EFI_ERROR(Status
)) {
288 BootOrder
= ReallocatePool (BootOrderSize
, BootOrderSize
+ sizeof(UINT16
), BootOrder
);
289 // Add the new index at the end
290 BootOrder
[BootOrderSize
/ sizeof(UINT16
)] = BootOption
->LoadOptionIndex
;
291 BootOrderSize
+= sizeof(UINT16
);
293 // BootOrder does not exist. Create it
294 BootOrderSize
= sizeof(UINT16
);
295 BootOrder
= &(BootOption
->LoadOptionIndex
);
298 // Update (or Create) the BootOrder environment variable
299 Status
= gRT
->SetVariable (
301 &gEfiGlobalVariableGuid
,
302 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
307 // We only free it if the UEFI Variable 'BootOrder' was already existing
308 if (BootOrderSize
> sizeof(UINT16
)) {
309 FreePool (BootOrder
);
312 *BdsLoadOption
= BootOption
;
318 IN BDS_LOAD_OPTION
* BdsLoadOption
,
319 IN UINT32 Attributes
,
320 IN CHAR16
* BootDescription
,
321 IN EFI_DEVICE_PATH_PROTOCOL
* DevicePath
,
322 IN ARM_BDS_LOADER_TYPE BootType
,
323 IN UINT8
* OptionalData
,
324 IN UINTN OptionalDataSize
328 CHAR16 BootVariableName
[9];
330 // Update the BDS Load Option structure
331 BootOptionSetFields (BdsLoadOption
, Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
333 // Update the related environment variables
334 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BdsLoadOption
->LoadOptionIndex
);
336 Status
= gRT
->SetVariable (
338 &gEfiGlobalVariableGuid
,
339 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
340 BdsLoadOption
->LoadOptionSize
,
341 BdsLoadOption
->LoadOption
349 IN BDS_LOAD_OPTION
*BootOption
355 UINTN BootOrderCount
;
356 CHAR16 BootVariableName
[9];
359 // Remove the entry from the BootOrder environment variable
360 Status
= GetGlobalEnvironmentVariable (L
"BootOrder", NULL
, &BootOrderSize
, (VOID
**)&BootOrder
);
361 if (!EFI_ERROR(Status
)) {
362 BootOrderCount
= BootOrderSize
/ sizeof(UINT16
);
364 // Find the index of the removed entry
365 for (Index
= 0; Index
< BootOrderCount
; Index
++) {
366 if (BootOrder
[Index
] == BootOption
->LoadOptionIndex
) {
367 // If it the last entry we do not need to rearrange the BootOrder list
368 if (Index
+ 1 != BootOrderCount
) {
371 &BootOrder
[Index
+ 1],
372 (BootOrderCount
- (Index
+ 1)) * sizeof(UINT16
)
379 // Update the BootOrder environment variable
380 Status
= gRT
->SetVariable (
382 &gEfiGlobalVariableGuid
,
383 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
384 BootOrderSize
- sizeof(UINT16
),
389 // Delete Boot#### environment variable
390 UnicodeSPrint (BootVariableName
, 9 * sizeof(CHAR16
), L
"Boot%04X", BootOption
->LoadOptionIndex
);
391 Status
= gRT
->SetVariable (
393 &gEfiGlobalVariableGuid
,
394 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
399 FreePool (BootOrder
);